CSPは「最後の防波堤」ではない。それは「ブラウザというOSのカーネル境界」だ
多くのエンジニアがCSP(Content-Security-Policy)を「XSSを防ぐための単なるヘッダー」と勘違いしている。実務の最前線に立つ我々にとって、CSPは単なる文字列の羅列ではなく、ブラウザの実行エンジンに対する「メモリ空間の隔離と実行許可の厳密なプロトコル」であるべきだ。
なぜなら、インジェクションの脅威は、もはや単なるalert(1)を出すような古典的なフェーズではない。攻撃者はDOMベースのXSSを通じ、生成AIのプロンプト・インジェクションを誘発し、ユーザーのセッションを乗っ取った上で、バックエンドのAPIに対して認証済みリクエストを送り込む。この時、CSPがなければ、ブラウザはその攻撃者のスクリプトを「正当なコンテキスト」として実行してしまう。
1. script-srcの「緩い設定」は、穴の空いた防弾チョッキと同じ
多くの現場で見かけるscript-src 'self' https://trusted.cdn.comという設定。これは、一見安全そうに見えて、実は現代の攻撃者にとっては「回避可能な障壁」に過ぎない。なぜなら、trusted.cdn.com上に古いバージョンのライブラリ(例えば、CVE-202X-XXXXが残っているAngularJSやjQuery)がホストされていれば、そこを起点としたDOM-based XSSで簡単にCSPをバイパスできるからだ。
真に強固な設計を目指すなら、Nonce(一時的な乱数)またはHashによるインラインスクリプトの制御が必須となる。
推奨される厳格なCSPヘッダーの構成例
Content-Security-Policy:
default-src ‘none’; # 原則禁止。ホワイトリスト方式を徹底する
script-src ‘nonce-EDNnf03nceIOfn39fn3e9h3sdf’ ‘strict-dynamic’; # Nonceで許可し、信頼されたスクリプトからの動的ロードを許容
object-src ‘none’; # プラグイン実行は論外
base-uri ‘self’; # 攻撃者によるURLハイジャックを防ぐ
connect-src ‘self’ https://api.production-domain.com; # API通信先を厳格化
frame-ancestors ‘none’; # クリックジャッキング防止
2. 「インラインスクリプト」という悪の根源を断つ
なぜunsafe-inlineが脆弱性診断で真っ先に指摘されるのか。それは、攻撃者が注入した任意のコードが実行される「ゲート」を開け放っているからだ。
我々アーキテクトが目指すべきは、「コードとデータの完全な分離」である。ReactやVueのようなモダンフレームワークを使っているなら、ビルド時に生成されるハッシュ値をCSPに埋め込むパイプラインを構築すべきだ。
もし既存のレガシーシステムで、どうしてもインラインスクリプトを排除できないのであれば、Strict CSPの導入を検討せよ。'strict-dynamic'ディレクティブを使うことで、信頼されたスクリプトが動的に生成する子要素までを「信頼の連鎖」として許可できる。これにより、個別のホスト名を列挙する泥沼の管理から脱却できる。
3. 生成AI時代の「防衛のパラダイム」
生成AIが生成したコンテンツ(ユーザー入力やサードパーティのAPIレスポンス)をDOMに展開する際、それが「プロンプト・インジェクション」の結果として悪意あるスクリプトを含んでいる可能性を考慮しなければならない。
ここで重要なのは、CSPを「ガードレイル」として使うことだ。
- サンドボックスの適用:
sandbox="allow-scripts allow-forms"を使用し、iframe内で危険なコンテンツを実行させることで、メインドメインのCookieやLocalStorageへのアクセスを遮断する。 - 信頼の連鎖を断つ: インジェクションされたスクリプトが、外部へのデータ送信を行おうとしても、
connect-srcによる制限があれば、攻撃者はデータを外部に持ち出せない。
4. 現場のアーキテクトへ:CSPは「静的」ではなく「運用」である
CSPの実装で最も失敗するのは、「一度設定して終わり」にすることだ。CSPにはreport-uriやreport-toディレクティブを設定し、違反ログをSIEM(SplunkやDatadogなど)に集約するパイプラインを必ず構築してほしい。
/ CSP違反ログの例(JSON形式で収集し、異常なアクセスを検知する) /
{
“csp-report”: {
“document-uri”: “https://secure-app.com/dashboard”,
“violated-directive”: “script-src”,
“blocked-uri”: “https://attacker-domain.com/malicious.js”,
“original-policy”: “script-src ‘self’ ‘nonce-…’ ”
}
}
このログを分析すれば、「開発者が意図せず外部CDNを読み込んでいる」のか、「実際に攻撃者がDOMを書き換えてスクリプトを差し込もうとしている」のかを、パケット構造やRefererの挙動から判別できる。
最後に:セキュリティは「完全性」の積み重ね
インジェクション攻撃を防ぐことは、もはや単なる「バリデーション」の域を超えている。メモリ上の実行フローを制御し、ブラウザの仕様を逆手に取り、攻撃者が「やりたいこと」を物理的に不可能にする。それが、我々が目指すべきセキュリティアーキテクチャの本質だ。
CSPは、OSのカーネルがプロセス空間を隔離するように、Webアプリケーションの実行コンテキストを隔離する。この「強固な境界線」を設計できる者だけが、増え続けるCVEや未知の攻撃手法に対して、静かに、そして確実に防衛の旗を掲げ続けることができるのだ。
さあ、あなたのアプリケーションのCSPを確認してほしい。そこには「緩い設定」という名の脆弱性が潜んでいないだろうか?
コメント