補足
この記事は旧徳丸浩の日記からの転載です(元URL、アーカイブ、はてなブックマーク1、はてなブックマーク2)。備忘のため転載いたしますが、この記事は2007年12月6日に公開されたもので、当時の徳丸の考えを示すものを、基本的に内容を変更せずにそのまま転載するものです。
補足終わり
最近、画像ファイルを用いたクロスサイト・スクリプティングが注目されている。本稿では、画像を悪用したXSSについて説明した後、対策方法について解説する。
画像によるXSSとはどのようなものか
Internet Explorer(IE)の特性として、コンテンツの種類を判別する際に、レスポンスヘッダ内のContent-Typeだけでなく、コンテンツの内容も判断基準にしている。このため、Content-Typeが例えばimage/gif(GIF画像)となっていても、中身がHTMLであればHTMLと解釈して表示する。このため、JavaScriptが埋め込まれていたら、JavaScriptを実行することになる。 例を示そう。このファイル(html.gif)は、拡張子は.gifなので、ダウンロードするとContent-Typeはimage/gifとなるが、内容はHTMLでありJavaScriptが埋め込んである。これをIEとFirefoxで表示した例を以下に示そう。IE7での表示 | |
Firefoxでの表示 |
先に示したhtml.gifは内容はhtmlテキストだけという素朴なものだが、イメージそのもの、パレット、コメントなどにhtmlやJavaScriptを仕込む手法が知られている(*1)。
対策の検討
IEがコンテンツの種類をどのように判別しているかは公開されていないようだが、たとえば2007年10月10日に公開されたマイクロソフト セキュリティ情報 MS07-057には以下のような記述がある。PNGs が MIME スニッフィング アルゴリズム の jpg/gif と同じ状態に昇格されます。例: サーバーが png のコンテンツの種類を送信した場合、Internet Explorer は magic-byte (マジックバイト) のテストを実行し、成功した場合、権限のあるサーバーの MIME の種類として処理します。意味のとりにくい日本語(機械翻訳?)だが、どうもコンテンツの種類判別にIEがマジックバイトを利用しているらしいことがわかる。
マジックバイトとは
マジックバイトとは、画像などのフォーマットを判別しやすいように、ファイルの先頭の数バイトに置かれた固定のデータである。GIF形式の場合であれば、"GIF87a"あるいは"GIF89a"で始まることになっており、先頭6文字を見ればGIF形式であることが容易に判別できる。下表に、主な画像形式のマジックバイトを示そう。画像形式 | BMP | GIF | JPEG | PNG |
---|---|---|---|---|
マジックバイト | BM | GIF8[79]a | \xFF\xD8 | \x89PNG\x0D\x0A\x1A\x0A |
IEのコンテンツ種類判別はContent-Typeとマジックバイトの組み合わせ
以上の情報などから、どうもIEのコンテンツ種類判別は、Content-Typeとマジックバイトの組み合わせにより決まるように思える。これを検証するために、主要な画像フォーマット4種(BMP、GIF、JPEG、PNG)のContent-Typeとマジックバイトの全ての組み合わせを試してみた。検証用に用いたサンプルデータは、マジックバイトとJavaScriptを組み合わせただけの簡単なものである。一例を下図に示す(GIF形式の偽画像)。結果は下表の通りである。表で、「HTML」となっている欄はHTMLと判別され、JavaScriptが起動するもの、「画像」となっているのは、画像と解釈しようとしたが表示できないため「×」表示となることを示している。これらはリンクとなっていて、実際のサンプルデータで試すことが出来るようにした。
画像種類 | マジックバイト | Content-Type | |||
---|---|---|---|---|---|
image/bmp | image/gif | image/jpeg | image/png | ||
BMP | BM | HTML | HTML | HTML | HTML |
GIF | GIF87a | HTML | 画像 | HTML | HTML |
JPEG | xFFxD8 | HTML | HTML | 画像 | HTML |
PNG | \x89PNG\x0d\x0a\x1a\0a | HTML | HTML | HTML | 画像(*2) |
対策:ではどうすればよいか
従来、画像XSSの対策には、イメージを他の形式に変換してから元の形式に戻す、あるいは竹迫氏のmod_imagefightのように画像中にXSS防御文字列を挿入するなど、さまざまな手法が提案されている。しかしながら、対策として不十分であったり、画質や処理速度の低下を招くなどさまざまな副作用があった。 マイクロソフトがMS07-057にてPNG画像のコンテンツ種別判定を改善してくれたことから、Content-Typeとマジックバイトの判定のみで、画像XSSを予防できる可能性が高くなった。 これでもまだ、BMP形式については改善がされておらず、画像XSSの危険性が残っている。コレに対しては、BMP形式画像のアップロードを許容する場合はPNGに変換して公開するというガイドラインを提案したい。BMP形式は通常画像が圧縮されていないので圧縮して公開した方が好ましいこと、BMPの特性(色数、可逆性など)はPNGで全てカバーしていることがその根拠である。 結論としては以下のようになる。 画像のマジックバイトとContent-Typeが同一の画像フォーマットに対するものであることを確認する MS07-057を適用する(ようにユーザに促す) 例えば、BMPを避ける。あるいはPNGに変換して公開する。謝辞:
画像埋め込みのHTML/JavaScriptについては、 はせがわようすけ氏からさまざまな情報を教授いただいた。記して、感謝の意を表する。
脚注
*1:JavaScriptを埋め込んだ画像を作ってみました参照
*2:MS07-057を適用していないとHTMLと解釈される
参考文献:
マイクロソフト セキュリティ情報 MS07-057
2007-07-15 - T.Teradaの日記 - 画像へのPHPコマンド挿入
TAKESAKO @ Yet another Cybozu Labs: LL魂お疲れ様でした[LLSpirit]
yohgaki's blog - 画像ファイルにPHPコードを埋め込む攻撃は既知の問題
本日のツッコミ(全3件)
□ はせがわ (2007年12月10日 13:54)はてなでの2004年の対策は、MS07-034のmhtml:に対する対策だったはずです。mhtml:をURLに付与することで、あらゆるリソースがRFC557のMHTML形式のドキュメントであると強制可能だったため、画像でも何でもbase64なスクリプトが埋め込み可能でした(なのでスタイルシート内でboundaryを削除している)。IEがContent-Typeを無視するというのとは、表面的・結果的には似ていますが、原理的には異なるものでした。
□ hoshikuzu (2007年12月23日 16:26)
まさしくアレはmhtml対策でした。はてなに報告した人より。
□ えむけい (2008年08月30日 05:49)
IE8でサンプルデータを試してみたらBMPはすべてtext/plainで(JavaScriptは起動せず)、GIF/JPG/PNGはすべて壊れた画像アイコンで表示されました。
ようやく画像XSSも過去のものになりそうです。