【入門編】 HTTP Header Injection (HTTPヘッダインジェクション) とレスポンス分割 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!セキュリティの世界へようこそ。
ペネトレーションテスト(攻撃者の視点でシステムを点検する作業)の世界では、目に見えないデータの裏側にある「ルールの隙間」を突くテクニックがたくさん使われます。

今回は、その中の一つである「HTTPヘッダインジェクション」と、そこから派生する「レスポンス分割」という攻撃についてお話しします。

「なんだか名前が難しそう……」と思いましたか?大丈夫です!身近な「郵便配達」と「手紙の封筒」の例えを使いながら、新人のIT担当者や開発者の方にもすっとイメージできるように、一歩ずつ優しく解き明かしていきますね。

それでは、さっそくセキュリティの冒険に出発しましょう!

—

1. 家の鍵と郵便受けに例える「HTTPヘッダ」の仕組み

まずは、私たちが普段何気なく使っているWebブラウザと、Webサーバーがどのように会話をしているのかを知る必要があります。

Webの世界では、ブラウザがサーバーに「このページをください!」とお願い(リクエスト)し、サーバーが「はい、どうぞ!」とお返事(レスポンス)を返します。このお返事の包み紙には、「HTTPヘッダー」と呼ばれる宛先や注意事項を書くスペースが用意されています。

身近な例え:郵便配達のルール

想像してみてください。あなたは実家のお母さんに手紙を送ります。
封筒の表には、宛先や「親展(本人以外が見ちゃダメ)」といった特別な指示(ヘッダー情報)を書きますよね。そして、その下に実際の便箋(ボディ、つまりWebページの中身)が入っています。

もし、配達員がその封筒を勝手に開けられて、宛先のところに「新しい手紙をもう1通、別の住所に送れ!」という偽の指示(改行コードと新しいヘッダー)を書き足されてしまったらどうなるでしょうか?

郵便局(ブラウザ)は、その偽の指示通りに動いてしまい、本来とは違う場所から荷物を受け取ったり、おかしな行動をとってしまいますよね。これが、HTTPヘッダインジェクションのイメージです。

—

2. 攻撃はどうやって起きる?(HTTPヘッダインジェクションの仕組み)

Webアプリケーションの中には、ユーザーが入力した文字(例えば、フォームに入れた名前や言語設定など)を、そのまま器用にHTTPヘッダーの一部として書き込んでしまう行儀の悪いプログラムが存在します。

ここに攻撃者が改行コード(コンピュータの世界で「ここで次の行にいきなさい」と指示する特殊な文字、具体的には \r\n や \n)をこっそり混ぜ込むと、サーバーはどう勘違いするでしょうか?

サーバーの勘違いが生む悲劇

サーバーはこう思います。
「あれ? ユーザーから入力された文字の途中で改行されているぞ。ということは、ここから先は『新しいHTTPヘッダーの続き』か、あるいは『ページの中身(ボディ)』の始まりだな!」

こうして、攻撃者が意図しない不正なヘッダー(例えば「別のページに強制的に飛ばす指示」や「ブラウザのセキュリティを無効化する指示」)が、あたかもサーバー自身が発信したかのようにねじ込まれてしまうのです。これがレスポンス分割(HTTP Response Splitting)の正体です。

—

3. 危険なコードの例と、その修正方法

それでは、実際の開発現場でやってしまいがちな「危ないコード」と、それをピカピカに安全にする「正しいコード」を見てみましょう。今回はWeb開発でよく使われるPHPを例にします。

【危険な例】ユーザーの入力をそのままヘッダーに使う

次のコードは、ユーザーがURLに入力した言語設定(lang)を、そのままページの移動先(Locationヘッダー)として使ってしまっている最悪の例です。

<?php
// ⚠️ 【危険な実装】ユーザーからの入力を検証せず、そのままヘッダーに渡しています
$user_lang = $_GET['lang'];

// もし $user_lang に改行コードが含まれていると、ヘッダーを勝手に追加されてしまいます
header("Location: /welcome.php?lang=" . $user_lang);
exit();
?>

このコードに対し、攻撃者が en\r\nSet-Cookie: session_id=hacked のような細工をした入力を送ると、サーバーは次のような不正なレスポンスを作ってしまいます。

HTTP/1.1 302 Found
Location: /welcome.php?lang=en
Set-Cookie: session_id=hacked

(ここに不正なコンテンツが続く)

これによって、ユーザーのブラウザが勝手に偽のクッキー(セッションID)を書き込まれてしまったり、悪意あるサイトへ誘導されたりするのです。

—

【安全な対策例】改行コードのブロックとバリデーション

では、どうやってこれを防げばよいのでしょうか?
答えは簡単です。「ユーザーから受け取った入力の中に、改行コード(\r や \n)が含まれていないか必ずチェックする」、そして「そもそも信頼できないデータを直接ヘッダーに組み立てない」ことです。

次のように書き換えてみましょう。

<?php
// ✅ 【安全な実装】入力値に改行文字が含まれていないか厳密にチェックします
$user_lang = $_GET['lang'];

// 改行文字(キャリッジリターンやラインフィード)が含まれている場合は処理を即座に中断
if (preg_match("/[\r\n]/", $user_lang)) {
    // ログに記録して攻撃を検知する
    error_log("HTTPヘッダインジェクションの兆候を検知しました: " . $user_lang);
    http_response_code(400);
    exit("不正なリクエストです。");
}

// 許可された安全な値のリスト(ホワイトリスト)と照合する
$allowed_langs = ['ja', 'en', 'fr'];
if (!in_array($user_lang, $allowed_langs, true)) {
    $user_lang = 'ja'; // 意図しない値ならデフォルトに戻す
}

// 安全が確認された値のみを使ってヘッダーを出力する
header("Location: /welcome.php?lang=" . $user_lang);
exit();
?>

このように、「怪しい文字(改行)をシャットアウトする」ことと、「あらかじめ許可された安全なリスト(ホワイトリスト)以外のものは受け付けない」という二段構えの防衛が、実務において非常に強力な盾になります。

—

4. 現場で役立つ防御ヘッダーの設定

アプリケーション側のコードを直すのと同時に、Webサーバーやリバースプロキシ(NginxやApacheなど)のレベルでも、不審なリクエストやレスポンスを弾く設定を取り入れておくとさらに安心です。

例えば、モダンなWebサーバーでは、そもそもURLやヘッダーに含まれる改行コードを自動的に拒否する機能が標準で備わっていることが多いですが、古いシステムを運用している場合は、WAF(Webアプリケーションファイアウォール)などを導入して、次のようなパターンをブロックできるようにルールを調整しておきましょう。

  • リクエストのヘッダーやパラメータに \r (CR) や \n (LF) が含まれていないか監視する
  • 予期せぬ改行によるレスポンスの分裂(Content-LengthやTransfer-Encodingの矛盾)が発生していないかチェックする

—

まとめ:一歩ずつ安全なコードを育てよう

今回は、HTTPヘッダインジェクションとレスポンス分割の仕組みについて、郵便の例えや具体的なコードを交えて解説しました。

ポイントをもう一度おさらいしておきましょう!
1. 仕組み: ユーザーの入力に混入した「改行コード」が原因で、サーバーやブラウザがレスポンスの構造を誤解してしまう攻撃。
2. 影響: キャッシュ汚染やクロスサイト・スクリプティング(XSS)、セッションの乗っ取りなどに繋がる危険がある。
3. 対策: 入力値に含まれる改行コード(\r, \n)を徹底的にチェックし、ホワイトリスト方式で安全な値だけを利用する。

セキュリティの対策と闻くと難しく感じるかもしれませんが、「信頼できない入力はそのまま信用せず、しっかり検閲する」という基本をコツコツ守るだけで、多くの脆弱性は綺麗に防ぐことができます。

ぜひ、今日からご自身の開発するコードやインフラ設定を見直してみてくださいね。一歩ずつ、安全で強いシステムを作っていきましょう!

コメント

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