はじめに
拙著「体系的に学ぶ 安全なWebアプリケーションの作り方」にはサポート用のメーリングリストがありますが、大変熱心に質問くださる方がいまして、熱心な質問だと余計に答えたくなります。そのうちの一つ(リンク)に回答しようとしてたところ、拙著内で説明が十分でないことに気がつきました。それは、
- HTTPヘッダインジェクション脆弱性を悪用して、セッションIDのCookiをセットして、そこからセッションIDの固定化攻撃を行う
という一連の手順です。HTTPヘッダインジェクションでCookieを改変できる説明とデモはありますが、そこからセッションIDの固定化攻撃については、以下のように、少しそっけない説明になっています。
外部から任意のクッキー値を生成されることの悪影響の例としては、4.6節で説明したセッションIDの固定化攻撃との組み合わせで、利用者に対する成りすまし攻撃が挙げられます。
脆弱性の素材としては、HTTPヘッダインジェクションもセッションIDの固定化もあるので、これらをつなぎ合わせたデモの手順を以下に説明しようと思います。以下の手順を試すためには、体系的に学ぶ 安全なWebアプリケーションの作り方の実習環境が必要ですが、拙作のBadTodo Listにも同じ脆弱性があるため、BadTodoで応用問題として試してみるのもよいでしょう。
脆弱性を試す
徳丸本の実習環境ではFirefoxを使いますが、以下の実習では、被害者と攻撃者でそれぞれ独立したブラウザを用意する必要があります。Google Chrome等でも大丈夫ですが、以下ではFirefoxのプライベートウィンドウを使いました。下図で、上が通常のウィンドウ(被害者)、下がプライベートウィンドウ(攻撃者)です。攻撃者側のブラウザはZAPなどは必要ありません。
被害者が罠URLを閲覧してしまう
被害者側のブラウザで、以下のURLを閲覧します。これは、シナリオとしては「攻撃者からメールなどで送られてくる罠のURLを被害者が閲覧してしまった」状態に相当します。
その際のHTTPレスポンスは以下のようになります。
HTTP/1.1 302 Found
Server: nginx/1.10.3
Date: Wed, 24 Sep 2025 11:44:34 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 292
Connection: keep-alive
Set-Cookie: PHPSESSID=ABC; path=/
Location: http://example.jp/463/46-010.php
以下省略
レスポンスヘッダの末尾2行だけを抜き出すと下図のようになります。
Set-Cookie: PHPSESSID=ABC; path=/
Location: http://example.jp/463/46-010.php
47-020.cgiは、クエリー文字列urlの値を「そのまま」リダイレクトします。そうすると、以下のヘッダが出力されるはずです。パーセントエンコードの部分はデコード済みです。
Location: http://example.jp/463/46-010.php[改行]Set-Cookie: PHPSESSID=ABC; path=/
[改行]と記した箇所は改行文字なので、実際に改行させると以下のようになります。
Location: http://example.jp/463/46-010.php
Set-Cookie: PHPSESSID=ABC; path=/
Locationヘッダ中の改行の作用により、Set-Cookieヘッダという第2のヘッダが現れます。このヘッダにより、PHPSESSIDというCookieがABCにセットされます。これがHTTPヘッダインジェクションの原理です。ブラウザに送信される時点で両ヘッダの順序が入れ替わっていますが、これはApacheによるものです。
被害者が正規サイトでログインする
リダイレクト先は、実習環境の「セッションIDの固定化」のデモプログラムです。以下の画面が表示されます。
これはログイン画面のつもりですが、デモなのでパスワードの入力は省略しています。しかし、こういうところで「なぜパスワードを入力しないのだろう」と詰まる人もいるようで、分かりやすいデモは難しいものだなと思います。それはともかく、ユーザID欄に、デモ用の文字列を入力します。下図では「secret-tokumaru」としていますが、この文字列には特に意味はありません。
ログインボタンを押すと、以下の表示になります。図示しているように、ログインが成功した「つもり」です。
「個人情報」のリンク(http://example.jp/463/46-012.php )をクリックすると下図の状態になります。「現在のユーザID」として、先程入力した値が表示されています。
この際のHTTPリクエストとHTTPレスポンスは以下のようになっています。
リクエストヘッダに「Cookie: PHPSESSID=ABC」があり、HTTPヘッダインジェクションによりセットしたCookieが有効になっていることが分かります。攻撃者は「被害者のブラウザではセッションIDがABCになっているはず」と想定しているため、自分自身のブラウザでセッションIDをABCにすると、被害者の個人情報が見られるはずです。以下、それを試しましょう。
攻撃者が自身のブラウザにCookieをセットして個人情報を盗む
シークレットモードのブラウザ(攻撃者のブラウザ)を開いて、以下のURL(上図と同じURL)を閲覧します。
まだCookieがセットされていないので、下図のように、ユーザIDの表示は空になっています。
ここで開発者ツール(Windowsをお使いの方はF12キー、Macの場合はCmd+Opt+Iキー)を開いて、ストレージタブを選び、左側のペインでCookieを選択します。PHPSESSIDがランダム文字列になっていますが、これをダブルクリックすると編集可能になるので、「ABC」と入力します。この状態でリロードボタンを押します。
上記の表示となり、被害者のブラウザで入力した値が表示されていることが分かります。同じセッションID(ABC)を共有しているので、セッション変数の値が漏洩していることがわかります。
一連のデモでは、以下の両方の脆弱性を使っています。
- HTTPヘッダインジェクション脆弱性
- セッションIDの固定化脆弱性
なので、どちらか一方の脆弱性をなくせば、デモで示した攻撃はできなくなります。とはいえ、それぞれ単体での悪影響もあり得るので、両方の脆弱性に対応しておくべきです。
HTTPヘッダインジェクション脆弱性の対策
PHP等の最新版では言語側で対策されいます。このため脆弱性サンプルではCGIプログラムにより「わざとらしい」再現をしています。汎用的な対策としては、HTTPレスポンスヘッダに出力する際に改行をチェックしてエラーにするか、パーセントエンコードすることで対策できます。IPAの「安全なウェブサイトの作り方」も参考になります。
セッションIDの固定化脆弱性の対策
セッションIDの固定化の対策は、ログイン時にセッションIDを発行し直すことです。これにより、ログイン後のセッションIDは攻撃者の未知の値になるため攻撃はできなくなります。IPAの「安全なウェブサイトの作り方」も参考になります。
また、拙著「体系的に学ぶ 安全なWebアプリケーションの作り方」には、両脆弱性の詳しい説明があります。