CSPは「魔法の杖」ではない:Report-Onlyモードで見極める攻撃の兆候と防御の境界線
セキュリティアーキテクトやテックリード諸氏であれば、一度はCSP(Content Security Policy)の導入で挫折した経験があるはずだ。「厳格なポリシーを適用した途端、レガシーなインラインスクリプトが死に、サードパーティの計測タグが全滅し、運用チームから非難の嵐が届く」。この光景は、現場では日常茶飯事だ。
しかし、なぜ我々はCSPを導入しなければならないのか。SQLインジェクションやクロスサイトスクリプティング(XSS)といったインジェクション攻撃は、現代のWebアプリケーションにおいて、単なる「脆弱性」の枠を超え、クライアントサイドの実行権限を乗っ取るための「橋頭堡」と化しているからだ。
今回は、単なる教科書的な導入手順ではなく、実戦で生き残るための「CSP Report-Onlyモード」を軸とした、防御の深層防御アーキテクチャについて語る。
—
1. なぜ「Report-Onlyモード」が必須なのか
CSPは強力だが、設定ミスは即座にビジネスを停止させる。本番環境でいきなり強力なポリシー(script-src 'self'など)を適用するのは、ブレーキの効き具合を確認せずに高速道路へ飛び出すようなものだ。
Content-Security-Policy-Report-Onlyヘッダーは、ブラウザに対して「ポリシーを強制はしないが、違反が発生したらレポートを送れ」と命じる。これは、攻撃者がどのようなインジェクションを試みているのか、あるいは自社の開発チームがどのような野放図なインラインスクリプトを埋め込んでいるのかを可視化する「鏡」となる。
実践的な設定例(HTTPレスポンスヘッダー)
最初はReport-Onlyモードで開始し、レポート収集エンドポイントへ送信させる
Content-Security-Policy-Report-Only:
default-src ‘self’;
script-src ‘self’ https://trusted-cdn.com;
object-src ‘none’;
report-uri /api/security/csp-reports;
この設定により、既存のアプリケーションがどの程度ポリシーに適合しているか、あるいはどのスクリプトがブロック対象となるかを、本番稼働を止めずに精緻にログ収集できる。
—
2. ログの向こう側にある「攻撃の予兆」を読み解く
収集したJSON形式のレポートを眺めていると、単なる「設定ミス」以外のものが見えてくる。
例えば、攻撃者は往々にして、eval()やsetTimeout()に渡される文字列のインジェクションを試みる。CSPのレポートには、違反したスクリプトのソースだけでなく、「どのドメインから、どのパスに対して、どのような意図で実行されようとしたか」が記録される。
{
“csp-report”: {
“document-uri”: “https://example.com/search”,
“blocked-uri”: “https://evil-attacker.com/malicious.js”,
“violated-directive”: “script-src-elem”,
“original-policy”: “script-src ‘self'”,
“status-code”: 200
}
}
このレポートが大量に発生している場合、それは単なるCSPの未対応ではなく、「既存の入力フォームを介したDOMベースXSSの試行」である可能性が高い。 脆弱性スキャナや攻撃者が、サードパーティのライブラリや動的なコンテンツ生成を悪用しようとしている兆候だ。
—
3. 生成AI時代の新たな脅威:プロンプトインジェクションへのガードレイル
昨今、多くのアプリケーションがLLM(大規模言語モデル)を統合している。ここで懸念すべきは、生成されたテキストがブラウザ上で実行可能なスクリプトとして解釈されるケースだ。
従来のCSPは、サーバーサイドからのレスポンスを制御するが、クライアントサイドでAIが生成した「推論結果(文字列)」が、DOM操作を通じてスクリプトとして注入される場合、単なるscript-srcだけでは不十分だ。
ここでアーキテクトが考えるべきは、「Nonce(ナンス)」ベースのCSPである。
Nonceを活用した防御アーキテクチャ
すべての実行スクリプトにサーバーサイドで生成した一意のトークン(Nonce)を付与する。
CSPヘッダーもこれに合わせて更新する。
Content-Security-Policy:
script-src ‘nonce-EDNnf03nceIOfn39fn3e9h3sdf’ ‘strict-dynamic’;
'strict-dynamic' を組み合わせることで、信頼されたスクリプトが動的にロードする子要素も自動的に信頼されるようになり、柔軟性と堅牢性を両立できる。
—
4. 最後に:インシデントに強い組織を作るために
CSPの運用は、設定して終わりではない。それは「守りのための継続的な観測」だ。
1. 段階的な適用: Report-Only でログを分析し、ホワイトリストを完成させる。
2. レポートの監視: 異常なスパイク(攻撃の兆候)を検知するためのアラートを構築する。
3. CI/CDパイプラインとの統合: 新しいスクリプトが追加された際、CSPポリシーに違反していないかをデプロイ前に自動テストする。
「完璧なセキュリティ」など存在しない。しかし、CSPを正しく理解し、Report-Onlyモードを通じてアプリケーションの「通信の癖」を完全に掌握しているアーキテクトは、インシデントが発生した際に、それが「攻撃」なのか「設定ミス」なのかを数秒で見抜くことができる。
その瞬間に見抜けるかどうかが、重大な情報漏洩を食い止める最後の防波堤になるのだ。
コメント