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

HTTPヘッダーインジェクション:制御不能な「改行」が招くプロトコルの崩壊

ネットワークエンジニアとして現場を歩いていると、往々にして「なぜそんな単純な入力値が、システム全体を揺るがすのか」という事態に直面します。HTTPヘッダーインジェクションは、まさにその代表格です。

HTTP/1.1において、ヘッダーの区切りは単なる記号ではありません。それは通信の「境界線」そのもの。この境界を攻撃者が自由に操れたとしたら?今回は、CRLF(Carriage Return + Line Feed)という、古くて新しい脆弱性の核心に迫ります。

—

1. 脆弱性のメカニズム:CRLFがもたらす「分断」

HTTPプロトコルにおいて、ヘッダーの終わりは `\r\n` (CRLF) の連続によって定義されます。サーバーがユーザーからの入力を適切にサニタイズせず、そのままヘッダー値として出力してしまった場合、攻撃者は意図的にこのシーケンスを挿入することで、サーバーのレスポンス構造を「分割」します。

通信シーケンスの悪夢

通常、サーバーは以下のようなレスポンスを返します。

HTTP/1.1 200 OK
Set-Cookie: session_id=12345
Content-Type: text/html

ここで攻撃者が「ユーザー名」などのパラメータに `%0d%0a`(CRLFのURLエンコード表現)を仕込むと、サーバーは以下のように解釈してしまいます。

HTTP/1.1 200 OK
Set-Cookie: user=hacker%0d%0aContent-Length: 0%0d%0a%0d%0aHTTP/1.1 200 OK%0d%0aContent-Type: text/html%0d%0a…

結果として、ブラウザや中間キャッシュサーバーは、本来存在しない「2つ目のレスポンス」を受け取ることになります。これがレスポンス分割攻撃(HTTP Response Splitting)の正体です。

—

2. なぜこれが脅威なのか:キャッシュ汚染の恐怖

レスポンス分割が単なる「いたずら」に留まらない理由は、キャッシュ汚染(Cache Poisoning)にあります。

CDNやプロキシサーバーは、ヘッダーを見て「どのリクエストに対するキャッシュか」を判断します。攻撃によって生成された偽のレスポンスがキャッシュサーバーに保存されると、以降、正当なユーザーが同じURLにアクセスしても、攻撃者が仕込んだ偽のコンテンツや悪意のあるCookie情報が返され続けることになります。これはもはや、インフラレベルの侵害です。

—

3. 実践:攻撃のデバッグと脆弱性の確認

現場でこの脆弱性が存在するかを確認する際は、`curl`を使って「意図的な改行」を注入してみるのが最も手っ取り早い手法です。

疑わしいエンドポイントに対してCRLFを注入するテスト例
サーバーが適切にバリデーションしていれば、%0d%0aは単なる文字として処理されるはず
curl -v “https://api.example.com/login?redirect=/%0d%0aX-Injected: True” 2>&1 | grep “Injected”

もし、出力結果に `X-Injected: True` というヘッダーがレスポンスに含まれてしまえば、それは「赤信号」です。即座にアプリケーション側の入力バリデーションを見直す必要があります。

—

4. 防御策:現代的なWeb開発の鉄則

この脆弱性を防ぐのは難しくありません。しかし、一つでも漏れがあれば全滅です。

アプリケーション層でのバリデーション

最も重要なのは、ユーザー入力をヘッダーに直接含めないこと、そして含める必要がある場合はCRLFを徹底的に除去することです。

Python (Flask) での安全な実装例を挙げます。

from flask import request, make_response
import re

def safe_set_header(key, value):
# CRLFが含まれていないか厳密にチェック
if re.search(r'[\r\n]’, value):
raise ValueError(“ヘッダーに改行コードが含まれています”)
return value

利用例
response = make_response(“Login Success”)
user_input = request.args.get(‘user’)
危険な入力を排除してからヘッダーにセットする
response.headers[‘X-User-Name’] = safe_set_header(‘X-User-Name’, user_input)

インフラ層での防御(WAFの活用)

アプリケーションの修正が追いつかない場合、あるいは多層防御の一環として、WAF(Web Application Firewall)でヘッダーの異常を検知・遮断するのが定石です。

  • AWS WAFの場合: 「HTTPヘッダーインジェクション」を検知するルールセットを適用する。
  • Nginxの場合: そもそもヘッダーに改行を含むリクエストを拒否する設定を検討する。

Nginxで不正な改行を含むリクエストを拒否する一例
(厳密にはバリデーションが必要ですが、基本的なガードになります)
ignore_invalid_headers on;

—

最後に:ネットワークエンジニアとしての視点

HTTP/1.1は非常に柔軟なプロトコルですが、その「自由度」が時として脆弱性の温床となります。HTTP/2以降はフレーム単位での通信が行われるため、この種のCRLFインジェクションの影響は限定的になりますが、バックエンドのコンポーネントがまだHTTP/1.1で会話しているケースは現場に溢れています。

「入力値はすべて疑え」。この格言は、パケットがどこを通過しようとも変わりません。あなたの書くコードや設定が、ネットワークという巨大な信頼の基盤を支えていることを忘れないでください。何かトラブルがあれば、まずはパケットをキャプチャし、その中身(ヘッダーの区切り)を疑うところから始めてみましょう。それが、真のエンジニアの第一歩です。

コメント

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