【入門編】 HTTP Response Splittingの仕組みとヘッダーインジェクション対策 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

こんにちは!セキュリティの世界へようこそ。これから一緒に、Webアプリの裏側でこっそり起こる面白い(そして怖い)攻撃と、そのスマートな防ぎ方について見ていきましょう。

エンジニアとして働き始めると、「入力値のチェックをしっかりしようね」「ヘッダーを設定しようね」と先輩から口酸っぱく言われますよね。「なんでそんなに細かいこと言うんだろう?」って、最初は少し面倒に感じてしまうこともあるかもしれません。

でも大丈夫です。今回は、家の鍵と泥棒の例えを交えながら、HTTP Response Splitting(HTTPレスポンス分割)という攻撃の仕組みと、その対策を優しく紐解いていきます。一歩ずつ、一緒に学んでいきましょう!

—

1. 例え話で理解する「HTTP Response Splitting」の世界

まずは、私たちの身近な「お家」を想像してみてください。

あなたが住んでいる家には、玄関のドアがありますよね。訪問客が来たら、あなたはドアを開けて「こんにちは!」と声をかけます。ここで大切なのは、「ドアの向こうから何を言われても、家の中のルールはあなたが決める」ということです。

もし、泥棒がやってきて、郵便受けの隙間から勝手に「この家は今日から全員お出かけでーす!鍵は開けっ放しですよー!」という偽の貼り紙をあなたの代わりに勝手に差し込んだとしたらどうでしょう? それを見たご近所さんは、本当に家が空き家になったと勘違いしてしまいますよね。

Webの世界で起きるHTTP Response Splittingも、これとまったく同じなんです。

Webの「お手紙」の仕組み

ブラウザ(あなた)とWebサーバー(お店)は、HTTPという決まり文稿(お手紙)をやり取りしています。

Webサーバーは、ブラウザからの「このページをちょうだい!」というお願いに対して、次のようなお返事(レスポンス)を書き込んで送り返します。

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8

こんにちは!ホームページへようこそ!

ここで注目してほしいのが、「ヘッダー(お返事のルール)」と「ボディ(本文)」の間に、目に見えない「改行(区切り線)」があることです。サーバーはこの改行を境にして、「上半分はルール書き、下半分は中身の本文」と綺麗に読み分けています。

攻撃者はどうやって「偽のルール」を挟むのか?

もし、このお返事の中に、ユーザーが入力した文字がそのまま入り込んでしまう仕組みがあったらどうでしょうか?

例えば、ユーザーの名前を受け取って「ようこそ、〇〇さん!」と画面に表示するプログラムがあったとします。ここで攻撃者は、名前に次のような「特別な記号(改行コード)」をこっそり混ぜて送信します。

山田さん\r\nLocation: https://evil.example.com\r\n\r\n<h1>ハックされました!</h1>

(※ \r\n は、パソコンの世界で「ここで改行してね!」を意味する暗号のようなものです)

サーバーがこの入力をうっかりそのままお返事に書き込んでしまうと、Webのお手紙は次のように強制的に分断(スプリット)されてしまいます。

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Location: https://evil.example.com

<h1>ハックされました!</h1>

おっと大変です!本来は「ようこそ!」と温かく迎えるはずのお返事が、改行コードのせいで別の意味にすり替わってしまいました。ブラウザは途中に現れた Location というヘッダーを見て、「あ、別の危ないサイトに引っ越せって言われたんだな」と勘違いし、攻撃者の用意した偽サイトへ自動的に連れていかれてしまいます。これが HTTP Response Splitting(HTTPレスポンス分割攻撃) の正体です。

—

2. 実装コードで見る脆弱性と危険な挙動

それでは、実際にどのようなコードを書くとこの罠にハマってしまうのか、PHPを例に見てみましょう。絶対に真似しないでくださいね(笑)。

❌ 危険なコード例(脆弱性あり)

以下のコードは、URLのパラメータから受け取った「リダイレクト先の名前」を、そのままお返事のヘッダーに設定してしまっている例です。

<?php
// URLのパラメータから 'page' という値を受け取る
$page = $_GET['page'] ?? 'index';

// ⚠️ 危険!ユーザーからの入力をそのまま 'Location' ヘッダーに組み立てている
header("Location: /welcomes.php?page=" . $page);
exit;
?>

このコードの何が問題か分かりますか?
$page の中身をチェックせずに、そのまま header() 関数に渡してしまっています。ここに攻撃者が \r\n(改行コード)を含む文字列を送り込むと、先ほど説明したお返事の分断が起きてしまうのです。

—

3. 一歩ずつ学ぶ!安全な対策とサニタイズ手法

「じゃあ、どうやって家を守ればいいの?」という話ですよね。
対策はとてもシンプルかつ強力です。基本方針はたったの2つ。

1. ユーザーからの入力を信用しない(入力値バリデーション)
2. ヘッダーに設定する前に、改行コードを徹底的に排除・無害化する(サニタイズ)

実際のPHPコードで、安全な書き方を確認してみましょう。

⭕ 安全なコード例(対策済み)

PHPの標準機能や条件分岐を使って、しっかりガードを固めたコードです。

<?php
// 1. ユーザーからの入力を受け取る
$page = $_GET['page'] ?? 'index';

// 2. ホワイトリスト方式(許可する値だけをあらかじめ決めておく)でチェックする
$allowed_pages = ['home', 'profile', 'settings'];

if (!in_array($page, $allowed_pages, true)) {
    // 許可されていない不正な値が来たら、強制的にデフォルトのページにする
    $page = 'home';
}

// 3. 万が一、改行コードが含まれていた場合に備えて、改行文字を削除・置換する
// (CRとLFを空文字に置き換えることで、レスポンス分割を物理的に不可能にする)
$safe_page = str_replace(["\r", "\n"], "", $page);

// 4. 安全になった値を使ってヘッダーを組み立てる
header("Location: /welcomes.php?page=" . urlencode($safe_page));
exit;
?>

ここがポイント!

  • ホワイトリスト方式:何でもかんでも受け入れるのではなく、「我が家に入れていいのはこの人たちだけ!」と名簿を作っておくのが一番安全です。
  • 改行コードの除去 (str_replace):万が一、変な文字が紛れ込んできても、改行(\r や \n)をその場で取り除いてしまえば、お返事を分断することはできません。これで泥棒の侵入経路を完全に断つことができます。
  • URLエンコード (urlencode):特殊な記号を安全な文字列に変換することで、予期せぬ挙動を防ぎます。

—

4. まとめ:今日からできるセキュリティの第一歩

HTTP Response Splittingという名前は難しそうに聞こえますが、要するに「お手紙のルールブックに勝手に落書きされないように、入り口でしっかり検閲しましょう」というお話でした。

実務の開発現場では、フレームワーク(LaravelやSymfonyなど)が最初から安全なヘッダー設定の仕組みを用意してくれていることが多いです。しかし、「フレームワークが裏で何をしてくれているのか」を知っているのと知らないのとでは、エンジニアとしての頼りがいが全く違いますよね。

今日からコードを書くときは、

  • 「この入力値、ユーザーが勝手に改行とか入れてないよね?」
  • 「ヘッダーに値を渡すときは、ちゃんとサニタイズされているかな?」

という視点をほんの少しだけ持ってみてください。それだけで、あなたの作るWebアプリケーションはぐっと堅牢で安全になります。

一歩ずつ、確実にスキルアップしていきましょう!応援しています!

コメント

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