備忘録

【.htaccess】CSP(Content Security Policy)を設定する方法

CSP(Content Security Policy)はHTTPヘッダの1つです。

なので、

  • .htaccessで指定(Apache)
  • metaタグで指定
  • 動的ページではPHPなどから指定

など方法は色々ありますが、ここでは.htaccessへの記述方法を解説します。

.htaccessへの記述方法

<IfModule mod_headers.c>
  Header set Content-Security-Policy "○○-src 'self'; ○○-src https://foo.com;"
</IfModule>

HTTPヘッダを設定するHeader setを使用するには、mod_headersモジュールが必要です。

具体的な記述例

<IfModule mod_headers.c>
  Header set Content-Security-Policy " \
    default-src 'none'; \
    script-src https://morisakimikiya.com/js/ \
               https://ajax.googleapis.com/ajax/libs/jquery/ \
               https://www.google.com/recaptcha/ \
               'sha256-*****'; \
    font-src https://fonts.gstatic.com/; \
    block-all-mixed-content; \
  "
</IfModule>
  • URLはシングルクォーテーションで囲まないよう気を付けてください。
  • 「\」は改行して続けるために書いています。
    半角スペース区切りで1行で書いても大丈夫です。
  • block-all-mixed-contentは、(httpsから)httpコンテンツを読み込むことを拒否する指示になります。

設定の手順

ホワイトリスト方式(DenyAllow方式)

上記の具体例では、default-src ‘none’で一度すべてを拒否しています。

すると、例えば以下のようなエラーがコンソールに表示されるはずです。

Refused to load the script ‘https://foo.com/bar.js’ because it violates the following Content Security Policy directive: “script-src ‘self'”.

「script-srcがselfに設定されているから、selfに含まれないhttps://foo.com/bar.jsは読み込むことができません」といった感じですね。

なのでこの場合であれば、

script-src ‘self’

script-src ‘self’ https://foo.com/bar.js

と修正すればOKです。

同様の手順で必要なリソースを1つずつ追加していきましょう。

Content-Security-Policy-Report-Onlyヘッダを活用する

ホワイトリスト方式では、一度すべてを拒否しています。

そのため、これまで特に設定を行っていなかった(=何でも許可していた)サーバーでは、その拒否したタイミングにユーザーが訪れた場合、jsが動作しない、画像が表示されないなどの問題が発生する可能性があります。

そのような問題を防止しつつCSPの設定を行いたい場合には、Content-Security-Policy-Report-Onlyヘッダを活用しましょう。

このヘッダは、簡単に言えば「ここで指定したもの以外でも読み込んでいいけれど、読み込んだ場合は何を読み込んだのかレポート(JSON形式)に残してね」というものです。

手順はホワイトリスト方式の場合と大きく変わりませんが、順に許可していくことで、最終的にレポ-トされるものが無くなればOKです。

詳しくはこちらをご確認ください。

参考:Content-Security-Policy-Report-Only – HTTP | MDN

インラインのスクリプトを個別に許可するには

sha-256ハッシュ値を設定する

インラインスクリプトの記述を許可していない場合、コンソールにこのようなエラーが出ます。

Refused to execute inline script because it violates the following Content Security Policy directive: “script-src *****”. Either the ‘unsafe-inline’ keyword, a hash (‘sha256-*****’), or a nonce (‘nonce-…’) is required to enable inline execution.

ここにハッシュ値が記載されているのでコピーし、記述例の’sha256-*****’の部分に埋め込めばOKです。

これは、登録したハッシュ値を持つスクリプトは実行を許可するということを行っています。

スクリプトが1文字でも改変されると、ハッシュ値は異なるものになるので、実行を防止できます。

逆にスクリプトを書き換えた場合は、ハッシュ値もあわせて修正しなければならないことには注意が必要です。

nonceを使う

ハッシュには、スクリプトを書き換えるとハッシュ値も修正しなければならないというデメリットがありました。

nonceを使えば、その必要はありません。

nonceは1度限りのトークンです。

このトークン(nonce)をヘッダとスクリプトタグの双方に埋め込みます。

クライアント側では、トークンの一致を確認してスクリプトを実行します。

メリット

  • 生成過程さえちゃんとしていれば、信頼性が高い
  • スクリプトを書き換えても、hashのように修正は必要ない

デメリット

  • PHPなどで動的に生成し、埋め込む必要がある(.htaccessでは書けない)
  • nonceを動的に埋め込んだファイルを送信することになるため、キャッシュが使えなくなる(静的サイト)

nonceについてさらに詳しく知りたい方は、こちらも参考にしてみてください。

参考:Content Security Policy Level 3におけるXSS対策 – pixiv inside

エラーが出る場合

  • ‘none’,’self’,’sha-256***’などはシングルクォーテーションで囲む必要があります。
    逆にURIは囲んではいけません。
  • ディレクティブはスペース区切りで、それぞれの最後にはセミコロンが必要です。
    カンマ区切りしていたり、セミコロンを忘れたりしていませんか?
  • .htaccessファイルは最後に改行が必要です。

参考

Content-Security-Policy – HTTP | MDN