【テクニカル・上級編】HTTPヘッダーインジェクションの攻撃ベクトル – HTTPプロトコル・通信規格実践ガイド

HTTPの闇:CRLFインジェクションが引き起こす「境界の崩壊」

ネットワークの現場において、HTTPは単なるデータ転送プロトコルではない。それは、クライアントとサーバーが「何を境界とするか」という暗黙の了解の上に成り立つ、極めて繊細な契約だ。HTTP/1.1まで続くプロトコルの歴史を紐解けば、この「境界」の定義がいかに脆いものかがよくわかる。

特に、HTTPレスポンス分割(HTTP Response Splitting)に代表されるヘッダーインジェクションは、プロトコルの根幹であるCRLF(`\r\n`)というシーケンスが、アプリケーションの不適切な処理によって「制御文字」から「データ」へと変質させられることで引き起こされる。

パケットレベルで紐解く、境界線の偽装

HTTP/1.1において、ヘッダーとボディの境界は明確に `\r\n\r\n` で定義される。サーバーがユーザー入力を検証せず、そのままレスポンスヘッダーに埋め込んでしまった場合、何が起きるか。

例えば、攻撃者が入力値として `%0d%0aContent-Length: 0%0d%0a%0d%0aHTTP/1.1 200 OK%0d%0a…` を送り込んだとしよう。サーバー内部のバッファでこの文字列が処理される際、パケットレベルでは以下のような「偽りの境界」が構築される。

HTTP/1.1 200 OK
Set-Cookie: user_input=%0d%0a <-- ここで注入が発生 Content-Length: 0 <-- 攻撃者が挿入した偽のヘッダー <-- 境界線(CRLFCRLF)を強制生成 HTTP/1.1 200 OK <-- 2つ目の偽レスポンス Content-Type: text/html ... この瞬間、プロキシサーバーやブラウザは、同一のTCPストリーム上に「2つのレスポンス」が存在すると誤認する。この「レスポンスの分離」が引き起こすキャッシュ汚染は致命的だ。意図しないレスポンスがキャッシュサーバーのメモリに居座り、後続の無実なユーザーに対して攻撃者のコンテンツを配布し続けることになる。

脆弱性を許すな:防衛のアーキテクチャ

この問題を解決するための第一歩は、アプリケーションコードにおける「CRLFの排除」ではない。それはあまりに脆弱な対症療法だ。真のインフラアーキテクトは、より上流で、かつ堅牢な防衛策を講じる。

1. 入力のバリデーション(ホワイトリスト方式)
入力値に対して、許可された正規表現以外の文字を一切受け付けない。ASCII制御文字を徹底的に弾くのが鉄則だ。
2. プロキシ/WAFでの正規化
Nginx等のリバースプロキシで、`merge_slashes` やヘッダーの不正なCRLF混入を検知するルールを設定する。

# Nginx設定例:不正なヘッダー文字を拒否する
# ヘッダー内のCRLFを検知して400を返す設定は必須
ignore_invalid_headers on;

# 必要に応じて、ngx_luaモジュールでヘッダーをサニタイズする
header_filter_by_lua_block {
local headers = ngx.resp.get_headers()
for k, v in pairs(headers) do
if type(v) == “string” and string.find(v, “\r\n”) then
ngx.exit(ngx.HTTP_BAD_REQUEST) — CRLFを含むレスポンスを遮断
end
end
}

パフォーマンスとセキュリティの二項対立を超えて

HTTPの脆弱性は、多くの場合「プロトコルの高速化」を追求する過程で露呈する。例えば、TLS 1.3でのハンドシェイク最適化やTCP Fast Open(TFO)を活用したRTT削減は、パケットの到達順序やバッファ管理に依存する。

TCPバッファのチューニング(`net.ipv4.tcp_rmem` など)を適正化し、輻輳制御アルゴリズム(BBRなど)を採用してスループットを最大化する際、ヘッダー圧縮アルゴリズム(HPACK/QPACK)が正しく実装されていない環境では、プロトコルスタックの僅かな解釈の差異がセキュリティホールとなる。

インフラスペシャリストへの提言:
「高速化」と「安全性」はトレードオフではない。むしろ、最新のHTTP/3(QUIC)環境へ移行することで、トランスポート層でのセキュリティ(TLS 1.3の強制適用)と、ストリームベースの多重化によるレスポンス分離の無効化(フレーム単位の制御による境界の厳格化)という、現代的な解法を手に入れることができる。

HTTP/1.1の設計思想を理解しつつも、脆弱なレガシーを放置せず、プロトコルスタックそのものをモダナイズし続けること。それが、我々アーキテクトに課せられた責務だ。パケットは嘘をつかない。嘘をついているのは、それを処理するアプリケーションのロジックであるということを、常に肝に銘じておいてほしい。

コメント

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