ブラウザの「XSSフィルター」はもう死んだ。現代のWeb開発者が負うべき真の防衛ライン
「ブラウザが勝手にXSSを防いでくれるから大丈夫」。もし新人の頃にそんな幻想を抱いていたなら、今すぐ捨ててほしい。
かつてChromeやIEには「XSS Auditor」や「XSS Filter」といった内蔵機能が存在していた。ブラウザがリクエストのパラメータを監視し、怪しいスクリプトの注入を検知したら即座にブロックする……一見すると魔法のような仕組みだったが、現実は甘くない。この機能は、巧妙に難読化されたペイロードによって簡単にバイパスされ、逆に「どのパターンならフィルターをすり抜けられるか」という攻撃者の踏み台にさえなっていた。
そして結論から言おう。現代の主要ブラウザから、これらの機能は完全に削除された。ブラウザの「お節介」に頼る時代は終わり、「自分のコードは自分で守る」というプロフェッショナルの責務が、かつてないほど重くなっている。
1. なぜ「ブラウザのガード」は無力だったのか?
攻撃者は、ブラウザのフィルターが「どの文字列を検知してブロックするか」を逆手に取る。
例えば、単純な は弾かれても、javascript:プロトコルや、DOMベースの難読化(String.fromCharCodeの利用など)を組み合わせれば、フィルターの正規表現をすり抜けるのは造作もないことだった。さらに、フィルターが誤検知(False Positive)を起こして正当な機能まで破壊するケースも多く、現場のエンジニアを悩ませる「負の遺産」と化していたのだ。
今、私たちが対峙すべきは、「反射型」「格納型」「DOM型」という古典的な三兄弟をベースにしつつ、それらが現代の複雑なフロントエンドフレームワークの中でどのように「実行可能コード」へ変換されるかという点だ。
2. 現代の防衛戦略:CSP(Content Security Policy)という要塞
ブラウザのフィルターが消えた今、最も強力な武器はサーバーから送るヘッダー、CSP (Content Security Policy) だ。これは「どのソースからスクリプトを読み込み、どこへの通信を許可するか」をブラウザに強制する指針である。
Nginxでの実装例
Nginxの設定ファイルに以下のヘッダーを追加するだけで、サイトの堅牢性は劇的に向上する。
CSP設定の例
‘self’:自ドメインからのスクリプトのみ許可
‘unsafe-inline’:インラインスクリプトを禁止(これがXSS防御の要)
‘unsafe-eval’:eval()等の危険な関数を禁止
add_header Content-Security-Policy “default-src ‘self’; script-src ‘self’ https://trusted-cdn.com; object-src ‘none’; base-uri ‘self’;” always;
開発者が直面する「壁」と解決策
'unsafe-inline' を禁止すると、 のようなコードが動かなくなるのはもちろん、HTMLに埋め込んだイベントハンドラ(onclick="...")も死ぬ。これこそが正しい状態だ。もし動かなくなったら、それは「脆弱なコードを書いている」という証拠。JSファイルへロジックを分離し、addEventListenerでイベントをバインドする設計へ書き換えるべきだ。
3. 実装の鉄則:出力時のエスケープと文脈依存
CSPはあくまで「最後の砦」。本丸であるアプリケーションコードでの防御を疎かにしてはならない。
PHPでの安全な出力例
PHPで最も危険なのは、エスケープ漏れだ。「とりあえず htmlspecialchars を使えばいい」と思っているなら要注意。引数の指定が重要だ。
こんにちは、” . h($user_input) . “さん
コメント