その「unsafe-inline」で本当に守れるか? CSPの盲点とプラグイン・ベースタグ攻撃の正体
現場でインシデント対応をしていると、よく目にする光景がある。「CSPを設定しました!」と胸を張るエンジニアのコードを見ると、script-srcにunsafe-inlineが鎮座し、肝心のobject-srcやbase-uriがスカスカに放置されているケースだ。
攻撃者は、君たちが「まさか」と思うような地味な入り口を徹底的に突いてくる。今日は、多くの開発者が軽視しているobject-srcとbase-uriの防御について、なぜこれが「最後の砦」になり得るのかを深掘りしよう。
—
1. なぜ「過去の遺物」を狙うのか?:攻撃のメカニズム
現代のWeb開発でFlashプレイヤーを見かけることは減った。しかし、攻撃者がobject-srcを狙う理由は「Flashを動かしたい」からではない。プラグインの読み込み機能を悪用し、ブラウザを意図しない外部コンテンツのレンダリングモードへ強制的に引きずり込むためだ。
base-uriによるパス・ハイジャックの恐怖
さらに恐ろしいのがタグの悪用だ。例えば、攻撃者がXSSなどでページ内にを挿入できたとする。すると、本来/js/app.jsを読み込むはずだった相対パスのスクリプトが、https://attacker.com/js/app.jsからロードされる。
これの何が危険か?
CSPのホワイトリストをすり抜け、攻撃者のスクリプトが「正当な読み込み」としてブラウザに処理される。base-uriを適切に制限していないと、どんなに強固なスクリプト制限も一瞬で無効化されるんだ。
—
2. 現場で使える「鉄壁」のCSPポリシー
理想的なCSPは、「デフォルトで全てを拒否し、必要なものだけを明示的に許可する」ことだ。まずは、Webサーバーの設定で以下のポリシーを適用してみてほしい。
Nginxでの設定例(nginx.conf または serverブロック)
CSPヘッダーの定義
object-src ‘none’: プラグインの実行を完全に禁止
base-uri ‘self’: ベースタグの指定元を同一オリジンに限定
add_header Content-Security-Policy “default-src ‘self’; object-src ‘none’; base-uri ‘self’; script-src ‘self’ https://trusted.cdn.com; style-src ‘self’ ‘unsafe-inline’;”;
なぜこれが必要なのか?
object-src 'none': これにより、プラグイン経由のコード実行や、ブラウザの挙動を歪めるプラグイン攻撃を根絶できる。base-uri 'self': 攻撃者が自身のサーバーを指すタグを差し込もうとしても、ブラウザはこれを拒否する。これにより、リソースの読み込み先が不正に書き換えられることを防ぐ。
—
3. 実践:PHPで動的にCSPヘッダーを制御する
静的な設定だけでなく、アプリケーションの動的な要件に応じてヘッダーを制御したい場合もあるだろう。以下はPHPでの実装サンプルだ。
/
function send_security_headers() {
// 厳格なCSPを定義
// ‘unsafe-inline’ は極力排除し、nonce(ナンス)を使用するのが現代のベストプラクティス
$csp = “default-src ‘self’; ” .
“object-src ‘none’; ” . // プラグインを完全排除
“base-uri ‘self’; ” . // ベースタグのハイジャックを防ぐ
“script-src ‘self’ ‘nonce-random123’; ” . // 信頼できるスクリプトのみ許可
“frame-ancestors ‘none’;”; // クリックジャッキング対策
header(“Content-Security-Policy: ” . $csp);
header(“X-Content-Type-Options: nosniff”); // MIMEタイプスニッフィングを防止
}
send_security_headers();
?>
—
4. プロの現場からのアドバイス:導入の心得
最後に、これらを導入する際の実務的なコツを伝えておく。
1. いきなり厳しくしない: Content-Security-Policy-Report-Onlyヘッダーを使って、まずはログを収集しよう。既存の機能が壊れないか確認するのが、インフラエンジニアの嗜みだ。
2. unsafe-inlineからの脱却: CSP導入の最大の壁はこれだ。全てのインラインスクリプトを外部ファイル化するのは骨が折れるが、nonce(使い捨てトークン)を活用すれば、インラインスクリプトを維持しつつ安全性を担保できる。
3. IAMとセットで考える: クラウド環境であれば、WAFのルール(AWS WAFのマネージドルール等)で不正なbaseタグの挿入を検知・ブロックするフィルタリングを併用するのが、多層防御の極意だ。
セキュリティは「魔法の杖」じゃない。地道な設定の積み重ねと、攻撃者の手口に対する想像力が、君のシステムを守る唯一の武器になる。今日紹介した設定を、今すぐ君のプロジェクトの構成管理ツールに組み込んでみてくれ。それが、一歩先を行くエンジニアへの第一歩だ。
コメント