【入門編】 HTTPヘッダーインジェクションの防止とレスポンス分割攻撃対策 – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

こんにちは!インフラやセキュリティの現場を渡り歩いてきたホワイトハッカーの私ですが、今回は新人のIT担当者や、セキュリティの勉強を始めたばかりの開発者に向けて、Webアプリの裏側でこっそり狙われる「HTTPヘッダーインジェクション」と「レスポンス分割攻撃」についてお話しします。

セキュリティの世界は小難しい専門用語が多くて萎縮してしまいますよね。でも大丈夫です。身近な「家の鍵」や「郵便受け」に置き換えて、一歩ずつ優しく紐解いていきましょう!

—

1. 郵便受けの悪夢:HTTPヘッダーインジェクションとは?

まずは、私たちが普段何気なく使っているWebブラウザとサーバーのやり取りを、身近な例えで考えてみます。

Webサイトを見るとき、あなたのパソコン(ブラウザ)は、お店(サーバー)に対して「このページをください」と手紙を出します。するとお店は、返事の手紙を書き、その封筒の「宛名や注意事項が書かれた部分(=HTTPヘッダー)」に様々な指示を書いてあなたに送り返します。

ここで想像してみてください。
もし、お店の郵便受けの構造がガバガバで、悪意ある人が外から勝手に封筒の宛名エリアへ「別の宛先」や「新しい手紙のルール」を書き足すことができたらどうなるでしょうか?

これが、HTTPヘッダーインジェクションという攻撃の正体です。

攻撃者は、ユーザーが入力するフォームなどに「改行コード」を含んだ特別な文字列を仕込みます。サーバー側がその入力値をそのままチェックせずに、レスポンスのヘッダー(封筒の宛名欄)に組み込んでしまうと、サーバーは「あ、ここで改行したから、次の行は新しい指示だな」と勘違いしてしまいます。

レスポンス分割攻撃(HTTP Response Splitting)の恐ろしさ

改行コードによってヘッダーエリアが強制的に終了させられると、その下には本来存在しない「新しいヘッダー」や、さらには「Webページの本体(HTML)」をねじ込むことができるようになります。

これがレスポンス分割攻撃です。
これに成功すると、攻撃者はユーザーのブラウザを別の詐欺サイトへ強制送還(フィッシング誘導)させたり、セッションIDを盗み取るための悪質なスクリプトを勝手に混ぜ込んだりすることができてしまいます。まるで、信頼しているお店からの手紙のなかに、見知らぬ泥棒からの脅迫状が挟み込まれているような状態ですね。

—

2. なぜ攻撃が成立してしまうのか?(メカニズムの裏側)

HTTPプロトコルでは、ヘッダーとボディ(本文)の区切りや、個々のヘッダーの区切りにキャリッジリターン(\r)とラインフィード(\n)という改行文字を使っています。

例えば、ユーザーからの入力値 name を、そのままリダイレクト先のURLを指定する Location ヘッダーに埋め込む次のようなPHPのコードがあったとします。

<?php
// 【危険な実装例】ユーザーの入力をそのままヘッダーに組み込んでいる
$user_input = $_GET['name'];
header("Location: /welcome.php?user=" . $user_input);
?>

ここで、もし攻撃者が name に以下のような文字列を入力したらどうなるでしょうか?

Taro\r\nSet-Cookie: SESSION_ID=evil_cookie

サーバーがこれを処理すると、実際に生成されるレスポンスのヘッダーはこうなってしまいます。

HTTP/1.1 302 Found
Location: /welcome.php?user=Taro
Set-Cookie: SESSION_ID=evil_cookie
<-- ここで勝手に新しいヘッダーが追加されている! -->

ブラウザはこれを「サーバーからの正しい指示だ」と信じ込み、勝手に悪意あるCookieを保存させられてしまいます。怖いですよね。

—

3. 現場で実践する!絶対に破られないための防御策

では、この巧妙な手口からWebアプリを守るためにはどうすればよいのでしょうか?
答えはとてもシンプルです。「ユーザーの入力値を、ヘッダーの構造を決める大切な場所にそのまま置かないこと」、そして「万が一紛れ込んでも、改行コードを徹底的に無力化(サニタイズ)すること」です。

一歩ずつ、具体的な対策を見ていきましょう。

対策①:ユーザー入力をヘッダーに直接含めない設計にする

そもそも、リダイレクト先やクッキーの値を、ユーザーが自由にいじれる入力値から直接組み立てる設計自体がリスクの温床です。基本的には、安全な内部のIDやセッション情報などをキーにして、サーバー側のデータベースやセッションから値を引き出すように設計を組み立て直しましょう。

対策②:改行コード(\r と \n)を徹底的に排除・置換する

どうしても入力値をヘッダーに反映させざるを得ない場合は、文字列の中に改行文字(\r や \n)が含まれていないかを厳しくチェックし、見つかった場合はエラーにするか、空文字に置き換える(サニタイズする)処理を必ず挟みます。

安全なPHPの実装サンプルを見てみましょう。

<?php
// 【安全な実装例】
$user_input = $_GET['name'];

// 1. 改行コード(\r や \n)が含まれているかチェック、または除去する
// preg_replaceを使って、改行文字を空文字に置換します
$sanitized_input = preg_replace("/[\r\n]*/", "", $user_input);

// 2. サニタイズされた安全な値を使ってヘッダーを構築する
header("Location: /welcome.php?user=" . urlencode($sanitized_input));
exit;
?>

このように、preg_replace や言語ごとの専用関数を使って、改行コードをあらかじめ取り除く(あるいはエンコードする)ことが、泥棒の侵入を防ぐ頑丈な二重ロックとなります。

—

4. まとめ:安全なWeb開発を習慣にしよう

HTTPヘッダーインジェクションやレスポンス分割攻撃は、一見すると地味な脆弱性に見えるかもしれませんが、ひとたび悪用されるとユーザーを深刻な被害に巻き込む危険な攻撃です。

「ユーザーが入力したデータは、すべて信用ならない怪しい手紙である」というゼロトラスト(何も信じない)の意識を持つことが、エンジニアにとって一番の防衛策になります。

今回学んだ「改行コードを許さない」「入力値をそのままヘッダーに載せない」という基本原則をしっかり頭に入れて、日々のコーディングに活かしていきましょう。安全で信頼されるWebアプリケーションを一緒に作っていkaf(いきま)しょうね!

コメント

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