webアプリで画像データを直接出力する際、ファイル名の拡張子がなかったり、Content-Typeが誤っていても、ブラウザは、JPEGやPNG、GINF等の画像フォーマットに応じ、レンダリングし、表示してくれます。
「なぜ?」と思いつつも、これまで調べていませんでしたが、実体は、画像データの先頭数数バイトにあるマジックバイトで判定しているらしい。
画像フォーマット | MAGIC BYTE |
---|---|
BMP | BM |
GIF | GIF8[79]a |
JPEG | xFFxD8 |
PNG | \x89PNG\x0A\x0A\x1A\0A |
http://www.tokumaru.org/d/20071210.html
マジックバイトの一覧は↑こちらで、perlでマジックバイトによる判定例は↓こちら。
http://howtobeahacker.seesaa.net/article/141255226.html
(上記サンプルコードのマジックバイトと徳丸さんが記載するマジックバイトが少々、ことなる点が気になりますが...)
更に 古いIE?では、 Content-Type とマジックバイトが異なる場合、ファイルの内容から、そのファイルの種類を自動判定してくれるらしく、FOO.PNGというファイルの内容が
<script>alert('FOO!!!')</script>
のようにjavascriptを含む場合、XSSになってしまうと。
怖い話です。
http://www.mozilla.gr.jp/standards/webtips/webtips0033.html
<img src="foo.png">
のように、インラインで表示する場合は、validationを強化するとして
ユーザにファイルをダウンロードさせる場合は、HTTPのヘッダで
perl cgiでダウンロードさせるファイル名を指定 (RFC6266準拠版) - end0tknrのkipple - web写経開発
のように Content-Type: application/octet-stream ;
Content_Disposition: attachment を指定すればよいのかな?
マジックバイトに関連する脆弱性は、十分に理解できていないので、
次のurlをきちんと理解しなくては
http://www.tokumaru.org/d/20071210.html
http://www.mozilla.gr.jp/standards/webtips/webtips0033.html