HTTPレスポンス分割攻撃:プロトコル層の「意味論的乖離」を突く深層防衛論
HTTPレスポンス分割攻撃(HTTP Response Splitting)は、現代のWeb開発において「過去の遺物」のように語られることがある。だが、それは大きな誤解だ。HTTP/1.1の複雑なステートマシンと、アプリケーション層での不適切なデータハンドリングが交差する境界領域には、今なお深刻な脆弱性が潜んでいる。
本稿では、単なる「改行コードのサニタイズ」といった教科書的な話を超え、プロトコル仕様の裏側と、モダンなアーキテクチャにおける防御の勘所を技術的視点から解剖する。
—
1. プロトコル仕様の盲点:CRLFは「境界」である
HTTPレスポンス分割の根本原因は、HTTPメッセージの構造が「ヘッダ」と「ボディ」を区切るために、CRLF(\r\n)という単純なバイナリシーケンスに依存している点にある。
攻撃者は、アプリケーションがユーザー入力をヘッダ値(例: Set-Cookie や Location)に直接埋め込む挙動を悪用する。Location: /path?redirect=... というヘッダに対し、\r\nSet-Cookie: session=evil\r\n\r\n... を注入することで、以下のことが起こる。
1. レスポンスの分断: クライアント(または中継するプロキシ/CDN)は、注入された \r\n\r\n を「ヘッダ終了の合図」と誤認する。
2. 意図しないコンテキストの生成: 攻撃者は、本来存在しないはずの「2つ目のレスポンス」を捏造し、キャッシュポイズニングやクロスサイトスクリプティング(XSS)へ直結させる。
低レイヤの教訓
HTTP/1.1では、Content-LengthとTransfer-Encoding: chunkedの解釈順序の不一致(HTTP Request Smugglingの文脈と共通する)や、ヘッダ行のパースにおける許容度(Fuzzingによって発見されるパースの揺らぎ)が、依然として攻撃の温床となる。
—
2. 現代の防御アーキテクチャ:ガードレイルの設計
現代のアプリケーションにおいて、単一のバリデーションに依存するのは危険だ。防御は「多層的(Defense in Depth)」かつ「宣言的」であるべきだ。
A. アプリケーション層でのサニタイズ(言語組み込みの活用)
多くのモダンフレームワーク(Goのnet/httpやNode.jsのhttpモジュール)は、現在、ヘッダへの改行挿入を検知して例外を投げる設計になっている。しかし、レガシーなライブラリや独自のヘッダ構築ロジックを使用している場合は注意が必要だ。
// 安全なヘッダ構築の例(Go)
func SetSecureHeader(w http.ResponseWriter, key string, value string) {
// 根本的な対策:入力値から制御文字を完全に除去する
// ASCIIの制御文字(0x00-0x1F)とDEL(0x7F)を削除
cleanValue := strings.Map(func(r rune) rune {
if r < 32 || r == 127 {
return -1 // 除去
}
return r
}, value)
w.Header().Set(key, cleanValue)
}
B. インフラ層による「正規化(Normalization)」
アプリケーションがどれほど脆弱であっても、リバースプロキシやWAFでトラフィックを正規化することで、攻撃の伝播を遮断できる。
- NGINXの設定例:
ヘッダ値に改行が含まれる不正なリクエストを拒否する
現代のNGINXはデフォルトで厳しいが、明示的な設定が肝要
underscores_in_headers off;
ignore_invalid_headers on;
—
3. 生成AI時代のプロンプト・インジェクションとの対比
今、私たちが直面している「生成AIに対するプロンプト・インジェクション」と、この「HTTPレスポンス分割」は構造が酷似している。どちらも「制御データ(命令やヘッダ定義)」と「ユーザーデータ(入力)」が同じチャネルを流れる際に発生する、構造的な意味論の不整合だ。
耐量子暗号や高度な認証アルゴリズムを導入しても、この「境界の定義ミス」を修正しなければ、セキュリティ・アーキテクチャは崩壊する。生成AIのガードレイル設計においても、LLMへの入力に「構造的区切り」が含まれていないか、あるいはメタデータが挿入されていないかを監視する「セマンティック・ファイアウォール」の発想が不可欠だ。
—
4. チーフホワイトハッカーとしての提言
脆弱性を撲滅するためには、以下の監査基準をCI/CDパイプラインに組み込むことを推奨する。
1. HTTPパースの静的解析: 自社実装の通信コンポーネントがある場合、CRやLFを含む入力に対して「パースがどのように振る舞うか」を網羅したユニットテスト(Negative Test)を必須とする。
2. CDN/WAFのログ・アノマリ検知: 特定のレスポンスヘッダに改行コードが含まれるリクエストパターンを監視し、検知した瞬間にインシデントハンドラを起動する。
3. HTTP/2, HTTP/3への強制移行: HTTP/2以降はバイナリプロトコルであり、フレーム単位でヘッダを扱うため、従来のテキストベースの分割攻撃は事実上不可能になる。プロトコルレベルでの「モダン化」こそが、最もコスト対効果の高い防御となる。
セキュリティとは、仕様の隙間を埋める終わりのないパズルだ。コードを書くとき、それが「どのプロトコル上の、どのパースロジックに渡されるか」を常に想像してほしい。その想像力こそが、我々エンジニアを守る最大の武器になる。
コメント