CSP Level 3 (Strict CSP) を利用する

1. このページの目的

このページに、CSP Level 3 を設定する。

Strict CSP (厳格なCSP)というアプローチに従う。

※ 結局、以下のリンク先で説明されている内容を翻訳した感じになってしまいました。

参考:Strict CSP

1-1. Strict CSP のための準備

Strict CSP の考え方

Scrict CSP を適用するための準備

2. このページで出力しているCSP用のHTTPヘッダ

Strict CSP で説明されている内容を翻訳してまとめ直しています。

Content-Security-Policy:
  object-src 'none';
  script-src 'nonce-{random}' 'unsafe-inline' 'strict-dynamic' https: http:;
  base-uri   'none';
  report-uri https://misc.laboradian.com/
各設定についての説明
ソース 意味
object-src 'none'
  • <object>, <embed>, <applet> タグで埋め込まれたリソースを実行しない。
script-src nonce-{random} 'unsafe-inline'
  • 'nonce-{random}' がある場合、最新のブラウザでは unsafe-inline ディレクティブは無視される。nonce をサポートしていない古いブラウザでは、 unsafe-inline が表示され、インラインスクリプトを実行できるようになる。
script-src 'strict-dynamic' https: http
  • 'strict-dynamic' は、nonce などで許可されたスクリプトが他のスクリプトを読み込むことを許可する。
  • 'strict-dynamic' がある場合、https:http: のホワイトリストエントリは最新のブラウザでは無視される。古いブラウザでは、任意の URL からのスクリプトの読み込みを許可する。
'unsafe-eval'
  • eval() などの実行を許可する。
base-uri 'none'
  • <base> URI を無効にして、相対 URL から読み込まれたスクリプトの位置を変更されるのを防ぐ。
  • <base> タグを使っている場合は、base-uri 'self' でもよい(通常は安全なはず)。
report-uri
  • ポリシーへの違反が発生すると、指定された URL に報告される。
  • JSON形式のデータがPOSTメソッドによるリクエストで送信される。
ブラウザ毎の動作
ブラウザの種類 動作
最新のブラウザ
  • nonce 属性がポリシーヘッダに設定された値と一致するスクリプトと、適切な nonce を持つスクリプトによってページに動的に追加されたスクリプトのみを実行する。
CSP3 標準をサポートしていない古いブラウザ
  • nonce-*'strict-dynamic' キーワードを無視して [script-src 'unsafe-inline' https: http:] にフォールバックする。
  • XSS 脆弱性に対する保護よりも、アプリケーションが動作することを優先する。

3. 本ページで利用しているPHPコードとHTML

CSP用HTTPヘッダを出力するPHPコード

$nonce = base64_encode(random_bytes(20));
header(
  "Content-Security-Policy:"
  . "object-src 'none';"
  . "script-src 'nonce-$nonce' 'unsafe-inline' 'strict-dynamic' https: http:;"
  . "base-uri 'none';"
  . "report-uri https://misc.laboradian.com/"
);

<script> タグ部分のHTML抜粋

<script defer src="main.js" nonce="<?php echo e($nonce); ?>"></script>
<script defer src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/highlight.min.js"
        nonce="<?php echo e($nonce); ?>"  ></script>
<script nonce="<?php echo e($nonce); ?>">
window.addEventListener('DOMContentLoaded', (event) => {
  console.log('inline js');
  hljs.highlightAll();
});

4. 観察する

ブラウザで本ページのソースを開き、何回かリロードしてください。nonce 値が毎回変更されるのが分かります。

ブラウザの開発者ツールの Console パネルを見ます。CSP のエラーは発生していないはずです。

ブラウザの開発者ツールの Network パネルを開き、HTTPレスポンスヘッダを見て、Content-Security-Policy の値を確認します。

5. 参考