【実務・中級編】Content-Security-Policy (CSP) の設計と厳格なポリシー適用 – アプリケーションセキュリティ & 安全な開発防御ガイド

CSPは「お守り」ではない。XSSを無力化する「防壁」だ。

現場でコードをレビューしていると、CSP(Content Security Policy)を「とりあえず入れておく程度のヘッダー」と勘違いしているエンジニアが多すぎる。unsafe-inlineを許容して「はい、エラーが出なくなりました」と満足しているなら、それは玄関の鍵を開けたままセキュリティステッカーを貼っているようなものだ。

今日は、攻撃者がXSS(クロスサイトスクリプティング)を仕掛ける際の「心理」と「盲点」を踏まえ、現代Web開発で通用する「強固なCSP設計」について語ろうと思う。

—

1. 攻撃者はどこを狙うのか?(PoCのリスク)

XSSの目的は、多くの場合「セッションハイジャック」や「管理者の権限奪取」だ。脆弱なアプリでは、攻撃者は以下のように

unsafe-inline を許可した甘いCSPを設定していると、これらのスクリプトはブラウザによって「信頼できるもの」と見なされ、即座に実行される。あなたがどれほど強固な認証を実装していても、実行権限を持つJSがブラウザ上で動いてしまえば、ゲームオーバーだ。

---

2. 厳格なCSPの設計思想:NonceとStrict-Dynamic

「厳格なCSP」とは、「信頼できないスクリプトを一切実行させない」という哲学のことだ。これを実現するための鍵が nonce と strict-dynamic である。

実装の戦略

1. Nonce(乱数): サーバー側でリクエスト毎に使い捨てのトークンを生成し、許可されたスクリプトタグにのみ付与する。
2. Strict-Dynamic: Nonceが付与されたスクリプトから読み込まれる「子スクリプト」も自動的に信頼させる。これにより、依存関係の複雑なJSライブラリにも対応できる。

---

3. 実装サンプル:NginxとPHPでのセキュアな構成

まずはNginx側でベースとなるポリシーを定義し、PHP側で動的なNonceを生成するのが現場の定石だ。

PHP側の実装例(Nonceの生成と出力)


Nginx設定ファイル(堅牢なベースライン)

NginxでCSPヘッダーを強制する設定例
add_header Content-Security-Policy "
default-src 'self';
script-src 'nonce-ランダムな値' 'strict-dynamic' https:;
object-src 'none';
base-uri 'none';
frame-ancestors 'none';
upgrade-insecure-requests;
" always;

  • object-src 'none': Flash等の古いプラグインによる攻撃を完全遮断。
  • base-uri 'none': タグによるドメインハイジャックを防止。
  • frame-ancestors 'none': クリックジャッキング攻撃を無効化。
  • upgrade-insecure-requests: 全てのHTTP通信を強制的にHTTPSへ昇格させる。

---

4. レポート機能の実装:インシデントの予兆を捉える

CSPを導入した直後は、既存の機能が壊れる可能性がある。ここで重要なのが report-to または report-uri だ。

add_header Content-Security-Policy "default-src 'self'; report-uri /csp-violation-report-endpoint;";

サーバーサイドで /csp-violation-report-endpoint を作成し、JSON形式で送られてくる違反ログを収集する。「なぜブロックされたのか」を解析するまでがセキュリティエンジニアの仕事だ。 ログを溜め込み、分析し、ポリシーを微調整する。この泥臭いサイクルこそが、システムを「鉄壁」へと進化させる。

---

後輩エンジニアへ、最後の助言

CSPは「魔法の杖」ではない。XSSの根本的な原因は、ユーザー入力を適切にエスケープしていない、あるいはコンテキストに応じた出力処理をしていないことにある。

CSPはあくまで「万が一、脆弱性が残っていた場合の最後の防波堤」だ。

1. 入力値を信じるな(バリデーション)。
2. 出力値を信じるな(エスケープ)。
3. そして、CSPで蓋をせよ。

この三段構えができて初めて、胸を張って「セキュアな開発をしている」と言える。まずは今のプロジェクトのCSP設定を確認し、unsafe-inline の文字がないか探すことから始めてほしい。それが、君がプロのセキュリティエンジニアとして歩む第一歩だ。

コメント

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