反射型XSSの深淵:ブラウザの解釈能力を逆手に取る「文脈汚染」の構造
反射型XSS(Reflected XSS)を単なる「URLにスクリプトを埋め込む手法」と捉えているなら、それはあまりに短絡的だ。現場で起きているのは、ブラウザという極めて柔軟で、かつ「空気を読みすぎる」パーサー(解析器)に対する、巧妙なコンテキスト・インジェクションである。
我々が守るべきは、単なる文字列ではない。ブラウザが受け取ったレスポンスを「何として解釈するか」という、ステートマシンとメモリ上のDOM構築プロセスそのものだ。
1. 攻撃の解剖:プロトコルからパケット、そしてDOMへ
攻撃者はURLパラメータという「信頼された入り口」を利用するが、真の狙いはHTTPレスポンスのボディに埋め込まれたペイロードが、最終的にブラウザのHTMLパーサーによってどう解釈されるかという「文脈の崩壊」にある。
例えば、?q=というパラメータがそのまま
ここで重要なのは、「いつ、どの段階でブラウザがその入力を解釈するか」という点だ。
近年のブラウザは、HTML5の仕様に基づき、多少の構文エラーがあっても「よしなに」解釈する。この「寛容さ(Robustness)」こそが、XSSの温床だ。攻撃者は、単なるタグの挿入だけでなく、属性のコンテキスト(例: onmouseoverなどのイベントハンドラ)や、JavaScript変数の代入文の途中に割り込むことで、エスケープシーケンスをすり抜けるような難読化を施してくる。
2. 「無害化」という幻想:バリデーションの限界
多くの開発者は、入力値を正規表現でフィルタリングすれば安全だと信じている。だが、それは「ブラックリスト方式」の罠だ。攻撃者は常にパーサーの挙動の隙間を突く。
真の対策は、「出力時のコンテキストに応じたエンコーディング」に尽きる。入力値のバリデーションはあくまで「形式チェック」であり、セキュリティの主戦場は「出力」である。
コンテキストに応じたエンコーディングの実装例(Node.js / Express)
安易なreplace()で凌ぐのはやめろ。ブラウザの仕様に基づいたライブラリ(DOMPurifyなど)を使い、HTML、属性、JavaScript、CSSの各コンテキストを厳格に分離する必要がある。
// 悪い例: 危険なブラックリスト方式
const sanitize = (str) => str.replace(/
コメント