WordPressのインラインJavaScriptをなくして、Content Security Policyを設定

うちのテーマは今のこのデザインになるまでは、サードパーティーのテーマを使っていたんです。
で、そのテーマには脆弱性があってXSSが有効だったんですよー((゜Д゜;))

今は1から作った独自のテーマを使っていて、汎用的な拡張性(テーマに必要な画像等のアップロード機能やAJAX)や外部を参照する不明なコードはありません。
なのでテーマ経由の脆弱性はない感じなのです。

だけれど、XSSを防ぐセキュリティ関連のヘッダーを設定しておいた方が良いって事なのでApacheにヘッダーを追加してみました。
新しく追加したのはX-Content-Type-Options、X-XSS-Protection、Content-Security-Policyの3つで、どれもXSSを防ぐのに効果が高いもの。
X-Frame-Optionsだけはブログをiframeで表示されていたサイトがあったので設定済みでしたw

設定内容はこんな感じ。

Header always set X-Frame-Options SAMEORIGIN
Header always set X-Content-Type-Options nosniff
Header always set X-XSS-Protection "1; mode=block"
Header always set Content-Security-Policy "default-src 'self' *.wolfs.jp; script-src 'self' *.wolfs.jp; child-src 'self' data: www.youtube.com; style-src 'self' 'unsafe-inline' *.wolfs.jp; img-src 'self' data: *.wolfs.jp *.gravatar.com;"

 
で、今回躓いたのはContent Security Policy(CSP)の設定。

JavaScriptやCSSは以前から1つにまとめているので大した問題ではなかったのですが、CSPで「script-src 'self' *.wolfs.jp」のようにインラインスクリプトを許可しない設定だとWordPressが出力するコメント関連のスクリプトが動かなくなっちゃう。
かと言って許可するとXSSに対して弱くなり、CSPを設定しないのとあまり変わらないような結果になります。

うちの環境で見た感じ、主にWordPressが出力するインラインJavaScriptは、
 ・コメントフォームの隠しフィールド「_wp_unfiltered_html_comment_」
 ・コメントのある「返信」ボタンのonclick
のようです。

とりあえず、その辺を無効化して無効化した物を再度使用可能にするように作っていきます。
続きを読む

WordPress 4.6で追加されたdns-prefetchを無効化する

WordPress 4.6からヘッダーに<link rel="dns-prefetch" href="//s.w.org/">が追加されるようになりました。
見つけた瞬間サイトがクラックされたのか?!とヒヤっとしたけれど、s.w.orgはWordPressのショートドメインて事がわかって一安心しましたw

うちはWordPressの絵文字とかを使っていないのでs.w.orgのDNSプリフェッチは必要なし。
なのでこれを無効化してみました。

作成したPHPコードはこれ。

<?php
 
add_filter('wp_resource_hints', function ($urls, $relation_type) {
    if (is_admin() === false) {
        if ($relation_type === 'dns-prefetch') {
            return array();
        }
    }
 
    return $urls;
}, 10, 2);
 
?>

コードは簡単でwp_resource_hintsにフィルターをかけて、管理ページ以外かつタイプがdns-prefetchの場合は定義されている内容を空っぽにして返すって感じ。
管理ページの場合は、なにかあるとダメなので引数をそのまま返すようにしてあります。

全く使わないならremove_action('wp_head', 'wp_resource_hints');の方がはやいんじゃない?って思ったんだけど、なぜかこれが効かなかったのでadd_filterで対処する荒療治に。

ちなみに、この記事を書いた時の$relation_typeの種類はdns-prefetch、preconnect、prefetch、prerenderとありました。
詳しい動作を追いたい場合はwp-includes/general-template.phpの2800行付近にfunction wp_resource_hints()があるのでそこから見てください。

archive.isにアーカイブされたページで警告を表示する。

archive.isをブロックしたりして対策をしてもアーカイブされちゃう事があります。
その対策の間をぬってアーカイブされちゃったページに警告を表示するJavaScriptを作ってみました。

if (location.hostname != "yourdomain") {
    document.title = "[不正コピー]";
    document.getElementsByTagName("body")[0].innerHTML = "";
 
    var i, html = "";
    for (i = 0; i <3000; ++i) {
        html += "/// 不正コピーです! /// ";
    };
    document.getElementsByTagName("body")[0].innerHTML = html;
    html = null;
};

コードは簡単、location.hostnameを比較してyourdomain以外なら警告を表示するコードを実行するだけ。
動作内容はタイトルを「[不正コピー]」に変更し、BODYエレメント内容を全部削除し代わりに「/// 不正コピーです! ///」の文字を3000回並べます。
yourdomainはあなたのサイトのドメイン名に変更して下さい、変更しないと本物のサイトでこのメッセージが表示されて悲惨なことになりますw

JavaScriptなので当然JavaScriptを動作しないようにしてある環境では動きませんが、現在はJavaScriptが動かない環境の方が少ないのである程度の効果はあると思います。

序で・・と言ったらあれですが・・
この文字を表示する動作を重くしたい場合は以下のようにコードを変更するだけ。

if (location.hostname != "yourdomain") {
    document.title = "[不正コピー]";
    document.getElementsByTagName("body")[0].innerHTML = "";
 
    for (var i = 0; i <3000; ++i) {
        document.getElementsByTagName("body")[0].innerHTML += "/// 不正コピーです! /// ";
    };
};

これは文字が追加される毎にDOMのレンダリングが発生するのでレンダリング負荷が増えます。
低スペックのPCやモバイル端末ではクラッシュさせる事もできるかも。
本当に重くさせるのであれば無限ループ化すればOK。

ちょっと応用すればarchive.isのロボットを狙い撃ちでクラッシュさせアーカイブを中断させる事も可能です。