【実務・中級編】CSPディレクティブ: script-srcとnonce/hashの活用 – アプリケーションセキュリティ & 安全な開発防御ガイド

なぜ「CSP」を語るエンジニアが少ないのか?—その「面倒くささ」こそが脆弱性の温床だ

現場でコードをレビューしていると、いまだにContent-Security-Policy(CSP)を「設定してもどうせ突破されるし、画面が崩れるから無効でいいや」と放置しているチームに出くわす。これがどれほど危険か、君たちにはわかるか?

CSPを単なる「教科書的なおまじない」だと思っているなら、今すぐその認識を改めてほしい。CSPは、万が一XSS(クロスサイトスクリプティング)の脆弱性をコードに残してしまった際の「最後の防波堤」だ。今日は、攻撃者が最も好む「インラインスクリプト」を無力化しつつ、現代的なWebアプリを破綻させずに守り抜くための実装術を叩き込む。

—

1. 攻撃者はどこを狙うのか?:インラインスクリプトという「甘い罠」

多くのエンジニアがやりがちなのが、これだ。


もし攻撃者が ?name= を送り込んだらどうなる?ブラウザは「ああ、これは開発者が書いた正当なスクリプトなんだな」と勘違いして、その悪意あるコードを実行してしまう。これがXSSの基本だ。

CSPの script-src 'unsafe-inline' を許可している環境では、この攻撃は即座に成立する。では、どうすればいいか?答えはシンプルだ。「インラインスクリプトを一切禁止し、正当なものだけにnonce(ナンス)を振る」ことだ。

—

2. nonce(ナンス)による防御のメカニズム

nonceとは、リクエストごとに発行される「一度きりの使い捨てトークン」だ。サーバー側で生成し、CSPヘッダーとHTML内の




---

3. インフラレベルでの制御(Nginxの設定)

もしPHP側でヘッダーを制御するのが難しい場合は、NginxやWAFで動的に付与する方法もあるが、ベストプラクティスは「アプリケーションコード内でnonceを管理すること」だ。

Nginxで設定する場合、静的ファイルであれば設定可能だが、動的なnonceはNginx単体では限界がある。リバースプロキシとして使うなら、以下のようなヘッダーポリシーの基礎を徹底してくれ。

Nginx設定例:最低限のスクリプト攻撃を防ぐ厳格なポリシー
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-random12345'; object-src 'none'; frame-ancestors 'none';";

注:object-src 'none' を忘れるな。Flashなどの古いプラグインを悪用した攻撃を防ぐ鍵だ。

---

4. なぜ「hash」ではなく「nonce」なのか?

CSPには hash(SHA-256など)を使ってスクリプトをホワイトリスト化する方法もある。しかし、動的に生成されるJSが多いモダンなWebアプリでは、毎回コードのハッシュ値を計算してCSPを更新するのは現実的ではない。

  • nonce: リクエスト単位で変わるため、動的なコンテンツに最適。
  • hash: 静的で変更のないライブラリやスクリプトを固定する場合に最適。

基本的には、nonceをメインで使い、どうしても外部化できない静的スクリプトに対してのみhashを併用するのが、現場で最も運用が回る構成だ。

---

5. 最後に:エンジニアが守るべき「泥臭い掟」

CSPを導入すると、最初はコンソールがエラーで真っ赤になるはずだ。「外部のトラッキングタグが動かない」「Googleマップが消えた」といった悲鳴が上がるだろう。そこで心が折れてCSPをオフにする奴が敗北する。

1. Report-Onlyモードで始める: Content-Security-Policy-Report-Only ヘッダーを使って、まずはブロックせずにエラーだけをログに集めろ。
2. サードパーティを厳選する: script-src に https://trusted-cdn.com のようにドメインを雑に追加するな。可能な限り自ドメインでホストせよ。
3. UIライブラリの選定: VueやReactなど、インラインスクリプトを多用するフレームワークを使う場合は、それらがnonceに対応しているかドキュメントを確認しろ(最近のモダンFWは対応済みだ)。

セキュリティは「完璧な防御」を目指すものではない。「攻撃コストを最大化させ、諦めさせる」ためのプロセスだ。nonceを導入するだけで、君のアプリは数多ある脆弱なサイトの中で、格段に「割に合わないターゲット」へと進化する。

さあ、今日のデプロイからコードを一行ずつセキュアに書き換えていこうか。それが俺たちエンジニアの矜持だ。

コメント

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