公開日:2007年6月28日
独立行政法人情報処理推進機構
セキュリティセンター
本ページの情報は2007年6月時点のものです。
記載の資料は資料公開当時のもので、現在は公開されていないものも含みます。
「HTTPレスポンスによるキャッシュ偽造(HTTP response splitting)」は、HTTPレスポンスヘッダの一部分をプログラムから出力するようにしているWebアプリケーションに干渉して偽のHTTPレスポンスを生じさせて、各種のキャッシュ(プロバイダのキャッシュサーバ、組織のプロキシサーバ、Webサイトのリバースプロキシサーバ、ブラウザのキャッシュ等)にそのレスポンスを記録させることによって、ひとりあるいは複数のユーザに悪意のWebページを閲覧させる攻撃である。
このような攻撃を受け入れてしまうのは、Webアプリケーションが入力パラメータの値に基づいてHTTPヘッダの部分も生成している場合である。入力パラメータの値をそのままHTTPヘッダ中にエコーバックするのみでは、この攻撃を許してしまう。
参考:
この攻撃によって作られた悪意のキャッシュの内容は、次のようなことに悪用されるおそれがある。
Webアプリケーションは多くの場合、HTTPレスポンスのボディ部のみを書き出し、ヘッダ部はWebサーバソフトやアプリケーションエンジンが生成している。しかし、Cookieを発行する場合やリダイレクト先のURLを指定する場合など、Webアプリケーションが次のようなヘッダへの書き出しを行うようにしている場合がある。
Webアプリケーションが書き出すこれらのヘッダに悪意のデータを混入し、本来は存在しないHTTPレスポンスをWebサーバに送出させるのがこの攻撃の要点である。
HTTPレスポンスによるキャッシュ偽造は、次の要領で行われる。
ここで仮に次のようなプログラム呼び出しのURLに対し、
http://site/redirect?location=/dir/another-page.html
次のようなLocation:ヘッダが書き出されるとする。
Location: http://site/dir/another-page.html{Cr}{Lf}
例えば、このプログラムに対して攻撃者は、次のような文字列を入力パラメータに投入してくるのである。(ここでは複数行に分かれているがひとつにつながったURLとして与える。)
http://site/redirect?location=
/dummy%0AContent-Length%3A+0%0A%0AHTTP%2F1.1+200+OK%0ADate%3
A+Tue%2C+29+Aug+2006+05%3A23%3A48+GMT%0AContent-Type%3A+text
%2Fhtml%3B+charset%3DUTF-8%0AContent-Length%3A+69%0A%0A%3Cht
ml%3E%3Cbody%3E%3Ca+href%3D%22http%3A%2F%2Fbad-site%2Fbad-pa
ge%22%3Efake%3C%2Fa%3E%3C%2Fbody%3E%3C%2Fhtml%3E%0A
プログラムredirectが入力パラメータ中の改行コードに対処していなければ、次のようなHTTPレスポンスヘッダが出力される。
Location: http://site/dummy{Cr}{Lf}
Content-Length: 0{Cr}{Lf}
{Cr}{Lf}
HTTP/1.1 200 OK{Cr}{Lf}
Date: Tue, 29 Aug 2006 05:23:48 GMT{Cr}{Lf}
Content-Type: text/html; charset=UTF-8{Cr}{Lf}
Content-Length: 69{Cr}{Lf}
{Cr}{Lf}
<html><body><a href="http://bad-site/bad-page">fake</a></body></html>
この最初の3行分で第1のHTTPレスポンスが終わり、4行目から新しいHTTPレスポンスが始まるかのように見える。
「HTTPレスポンスによるキャッシュ偽造」ができないようにするためには、このようなWebアプリケーションは、入力データをHTTPレスポンスヘッダに書き出す際に、そこに含まれる改行コード(Cr および Lf)がそのまま出力されないようにする必要がある。
具体的な方法として、データ中から Cr や Lf を削除するやり方も考えられるが、HTTPヘッダ内に出力する値にURLエンコーディングを施すのが自然なやり方である。
header("Location: " . urlencode($value));
response.addHeader("Location: " + URLEncoder.encode(value));
URLエンコーディングを施すことにより、Cr は %0D で、Lf は %0A で表現されHTTPヘッダの中で特別な意味をもたなくなる。しかも、これらの値をURLとして扱ったり、再度Webアプリケーションがパラメータとして入力する場合も、URLエンコーディングをデコードして使うのが通常であるから、余分なロジックを必要としない。
なお、この対策は、プロキシサーバのキャッシュ偽造を根本から無くすものではない。別の攻撃手口によってプロキシキャッシュが汚染されることもありうる。
定期的にキャッシュをクリアする等、万一キャッシュが汚染された場合でも被害を小さく抑えるための運用を、プロキシサーバやキャッシュサーバ運用者が行うことが望ましい。
PHP 4.4.2 およびそれ以降のバージョンでは、HTTPレスポンスヘッダを書き出すためのheader()関数に与えられた引数に改行文字が含まれていると実行時エラー(警告レベル)として検出するようになった。