WAFは「魔法の盾」ではない:XSS検知の限界と、現場で本当にやるべき防衛戦略
エンジニアの諸君、現場で「WAFを入れてるからXSSは大丈夫」なんて言葉を耳にしたら、即座にそのプロジェクトの設計を見直したほうがいい。
誤解を恐れずに言おう。WAF(Web Application Firewall)は、あくまで「パッチを当てるまでの時間稼ぎ」あるいは「既知の攻撃を弾く防波堤」に過ぎない。 攻撃者は日々、君たちが設定した正規表現の「隙間」を縫うように進化しているんだ。今日は、なぜWAFのシグネチャが簡単に突破されるのか、そして我々がアプリケーション側で何を担保すべきか、現場の視点から紐解いていく。
—
1. なぜWAFは「難読化」に弱いのか
WAFの多くは、 や alert() といった既知のシグネチャを正規表現でマッチングさせている。だが、攻撃者はこれらを無効化するために、ブラウザの「寛容さ」を利用する。
例えば、こんなペイロードを見たことはあるか?
このペイロードは、タグを使わず、eval関数と文字コードを使って alert('XSS') を実行している。WAFの設定が「タグ名」や「危険な文字列」の単純なリストに基づいている場合、こうした難読化を前にして素通りしてしまう。
また、Base64エンコードや、意図的な改行、タグ内の空白文字()など、ブラウザが解釈できてWAFが解釈できない「解釈の揺らぎ」が、攻撃の入り口になるんだ。
---
2. 対策の核心:WAFに頼らない「多層防御」
WAFの設定をどれだけ細かくしても、いたちごっこは終わらない。結局のところ、「出力するデータが正しい文脈で扱われているか」をアプリケーション側で担保するのが唯一の正解だ。
実践:PHPにおける出力エスケープの鉄則
PHPで動的にHTMLを生成する場合、htmlspecialchars を使うのは基本中の基本だが、パラメータを間違えると意味がない。
実践:JavaScriptにおけるDOM操作の罠
最近のSPA開発で最も危険なのが、innerHTML の安易な使用だ。これを textContent に変えるだけで、XSSのリスクは劇的に減る。
// 危険:innerHTMLはタグを解釈してしまう
// const div = document.getElementById('output');
// div.innerHTML = user_input;
// 安全:textContentはすべて文字列として扱うため、スクリプトが実行されない
const div = document.getElementById('output');
div.textContent = user_input;
---
3. 防衛の最後の砦:Content Security Policy (CSP)
アプリケーションコードの修正が追いつかないレガシーなシステムであっても、CSP(Content Security Policy)というHTTPヘッダーを設定するだけで、攻撃の成功率を極限まで下げることができる。これはブラウザに対して「どのソースからのスクリプトなら実行していいか」を指示するものだ。
Nginxの設定例を置いておく。これを本番環境に適用するだけでも、攻撃者のモチベーションを大きく削げるはずだ。
Nginx設定ファイルに追加
'self':自ドメインからのスクリプトのみ許可
'unsafe-inline'を排除することで、
コメント