【実務・中級編】Content-Security-Policy (CSP) のscript-srcディレクティブ詳細設定 – アプリケーションセキュリティ & 安全な開発防御ガイド

脱・「とりあえずunsafe-inline」。CSPのnonce活用でXSSを根絶する

現場のエンジニア諸君、お疲れ様。
「XSS対策? ちゃんとエスケープしてるし大丈夫でしょ」。そうタカを括っているなら、今すぐ考えを改めたほうがいい。

現代の攻撃者は、君が書いたコードの「エスケープ漏れ」をピンポイントで突くような泥臭いことはしない。「信頼されているはずのライブラリの脆弱性」や「CDN経由で注入された悪意あるスクリプト」を悪用し、ブラウザを完全に制御下に置こうとしてくる。

これを防ぐ最後の砦が、Content-Security-Policy (CSP) だ。今日は、巷に溢れる「とりあえずunsafe-inlineを許可して動かす」という思考停止な運用を卒業し、nonceを用いた真に堅牢な防御の実装を叩き込む。

—

1. なぜ「エスケープ」だけでは不十分なのか?

XSSは反射型、格納型、DOM型と分類されるが、どれも共通のゴールは「攻撃者のスクリプトを、正当なオリジンのコンテキストで実行させること」だ。

もし君がDOM型XSSを仕込まれたらどうなるか? 攻撃者は、君が書いた正規のJSライブラリを悪用してDOMを操作し、認証トークンを外部サーバーへ送信する。このとき、サーバー側でのエスケープ処理は一切役に立たない。

そこで登場するのがCSPだ。「ブラウザに対して、どのソースからのスクリプト実行を許可するか」を厳格にルール化することで、仮に脆弱性があっても、攻撃者のコードを「実行させない」ようにする。

—

2. 禁断の「unsafe-inline」を排除せよ

多くのエンジニアが「動かないから」という理由で unsafe-inline を設定する。これは、警備員がいるはずの銀行の入り口に「誰でも自由に入っていいよ」と看板を掲げるようなものだ。

これを排除するための切り札が、nonce(ナンス:Number used once) だ。

nonceの仕組み

1. サーバーはリクエストごとに、推測不可能なランダム文字列(nonce)を生成する。
2. CSPヘッダに script-src 'nonce-RANDOM_VALUE' を付与する。
3. HTML内の にはnonceが付与されていないため、ブラウザは無視する。完璧だ。

---

3. 実践:PHPによるセキュアな実装サンプル

では、実務でどう書くか。以下はPHPでの実装例だ。







CSPで守られたページ



---

4. インフラ側でカバーする:Nginx設定のポイント

もしサーバーサイドでヘッダ制御が難しいレガシーな環境なら、WAFやNginxで制御することも検討すべきだ。ただし、Nginx単体では動的なnonce生成は難しいため、基本はアプリケーション側でヘッダを付与し、Nginxは「ベースとなるセキュリティヘッダ」を付与する役割に徹する。

Nginx設定例(最低限のヘッダ):

厳格なデフォルト設定
add_header Content-Security-Policy "default-src 'self'; object-src 'none'; frame-ancestors 'none'; sandbox allow-forms allow-scripts;" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;

---

5. 現場のセキュリティ担当者からのアドバイス

最後に、運用上の注意点を3つだけ伝えておく。

1. report-uri / report-to を活用せよ:
CSPでブロックが発生した際、JSONでレポートを送る設定を追加しておこう。開発環境で設定し、何がブロックされているか監視するだけで、君のアプリの「どこが危険な実装なのか」が可視化される。
2. CDNのライブラリにはハッシュを使え:
どうしても外部ライブラリを読み込む必要がある場合、nonceだけでなく sha256-ハッシュ値 を使う手法もある。特に頻繁に更新されないライブラリには有効だ。
3. 「完璧」を目指して止めるな:
最初から厳格なCSPを入れると、サイトが崩れることがある。まずは Content-Security-Policy-Report-Only ヘッダを使用して、ブロックされる内容をログに書き出すことから始めろ。

セキュリティは「魔法の杖」じゃない。「攻撃者がコストを払ってまで狙う価値のない、防御が堅いシステム」を構築し続けることが、我々エンジニアの使命だ。

さあ、今日から unsafe-inline を削除するタスクをバックログに追加してくれ。君のシステムがより堅牢になることを期待している。

コメント

タイトルとURLをコピーしました