BK通信 ―Bad Knowhow Tsushin―

#05 ブラウザのバッドノウハウ コンテンツ編

この記事を読むのに必要な時間:およそ 3.5 分

ソフトウェアなどを使いこなすために,ストレスを感じながらもしぶしぶ覚えなければならないようなノウハウ,「バッドノウハウ」がテーマの本連載,第5回の今回はブラウザのBKを,コンテンツの扱いに関連するものに絞って取り上げたいと思います。

IEのContent sniffing

通常,ブラウザはHTTPのレスポンスのContent-Typeヘッダに応じて,コンテンツをどのように処理するか決めますが,Internet Explorer 7(IE7)はこのヘッダを無視するときがあります注1)。

たとえば,リスト1のようなファイルをtest.txtという名前でWebサーバに置いて,IE7からアクセスすると,サーバからContent-Type:text/plain(ただのテキストファイル)として送られてきているにもかかわらず,HTMLとして解釈されてしまいます図1)。

リスト1 test.txt

#! /usr/bin/perl
print "<html><h1>hello, world</h1></html>"

図1 HTMLとして解釈された

図1 HTMLとして解釈された

同様の現象はtext/plainに限らず,image/jpegなどの画像のContent-Typeが指定されているときにも起きます。このような挙動はContent sniffingと呼ばれています注2)。

おそらく,この挙動はContent-Typeが間違っていてもコンテンツを正しく表示したい,という意図のもとに実装されているのだと思われます。しかし,Webアプリケーションの脆弱性につながる恐れがある挙動としても知られています。

先のリスト1の例では無害なHTMLタグが使われているだけですが,<script>タグでJavaScriptを埋め込むこともできます。これはユーザが任意のファイルをアップロードできるサイトで,とくに問題になります。テキストファイルや画像と見せかけて悪意のあるJavaScriptをアップロードして他人に開かせる,という攻撃が可能であるためです。

この自動判別の挙動は,IE8ではX-Content-Type-Options:nosniffというヘッダをHTTPのレスポンスに入れることで無効にできます。このような変な挙動は単に撤去すればいい気がしますが,この挙動に依存しているサイトを壊さないために互換性を維持しているのだと思います。

注1)
IE7.0.5730.13で動作検証しました。IE6でもおそらく同様ですが,手元に動作検証できる環境がないため,今回はIE7に絞って話を進めます。
注2)
Content sningに関する情報は以下が充実しています。
URL:http://webblaze.cs.berkeley.edu/2009/contentsniffing/

Content-Dispositionヘッダで解決?

前述した,本来のContent-Typeと異なる形式でコンテンツが解釈されてしまうという問題を回避するには,ブラウザにファイルを開かせる代わりに保存させればいいのでは,というアイディアがあります。具体的にはHTTPのレスポンスに,リスト2を加えます。このContent-Dispositionヘッダにより,ブラウザの中でコンテンツを開くのではなく,foo.txtというファイルとして保存せよ,とブラウザに伝えることができます。

リスト2 Content-Dispositionヘッダ

Content-Disposition: attachment;
 filename="foo.txt"

しかし,IEにはContent-Dispositionヘッダの扱いに過去に問題がいろいろあり注3),最近のバージョンでも問題が発見されているので注4),Content sningを防ぐためにContent-Dispositionに頼るのは安全ではありません。

危険性のあるテキストファイル注5の内容をどうしても表示させたい場合は,Content sningの影響を受けないように先頭の256バイトを空白で埋める注6),HTMLの特別な文字をすべて&lt;,&gt;などにエスケープした上でHTMLとして表示させる,といった方法があります。

ところで,Content-Dispositionというヘッダは元々,メールで使われているMIMEというフォーマットを拡張するために導入されたものであり,正式にはHTTPの仕様には含まれません。HTTP 1.1の標準であるRFC 2616を見ると,Content-DispositionはHTTPの標準の一部ではないと明記されています注7)。しかし,大半のブラウザはContent-Dispositionヘッダに対応しているので,RFC 2616の中でもこのヘッダの扱い方について言及されています。

注3)
たとえば以下によると,一部のIEのバージョンではテキストやHTMLの場合,Content-Disposition:attachmentが指定されていても,ブラウザ内で表示してしまったようです。
URL:http://support.microsoft.com/kb/267991
注4)
JavaScriptのhistory.back()と組み合わせる攻撃法が知られています。
注5)
ユーザがアップロードしたファイルなど。
注6)
以下によると,IEはコンテンツの先頭の256バイトでコンテンツの種類を判別します。
URL:http://msdn.microsoft.com/en-us/library/ms775147(VS.85).aspx
注7)
RFC 2616の15.5節「Content-Disposition Issues」より。

日本語ファイル名の問題

前節のリスト2で,Content-Dispositionヘッダのlenameパラメータで,ファイル名を指定できることを示しました。では,日本語のファイル名はどのように扱えばいいのでしょうか。これは,実は奥が深い問題です。

単純に考えると,リスト3のように日本語の文字をそのまま使えばいいような気がしますが,この場合,どの文字エンコーディングを使うかが問題になります。

たとえば,UTF-8を使うと,IE7では「縺ゅ>縺・txt」のようにファイル名が文字化けしてしまいます。

リスト3 日本語の文字そのまま

Content-Disposition: attachment;
 filename=" あいう.txt"

日本語ファイル名とメールの世界

メールの世界でも,添付ファイルの日本語ファイル名を扱うのはややこしい問題として知られています。多くのメーラはリスト4のようにエンコードします。

先頭の=?UTF-8?B?は文字エンコーディングがUTF-8であること,BASE64でデータがエンコードされていることを意味しています。このようなエンコード方式はRFC 2047で定義されており,encodedwordと呼ばれています。

リスト4 よくあるエンコード

Content-Disposition: attachment;
 filename="=?UTF-8?B?44GC44GE44GGLnR4dA==?="

実は,上のContent-Dispositionは厳密にはRFC 2047に違反しています。RFC 2047によると,encoded-wordは"(ダブルクォート)で囲まれた文字列の中に含めるのは禁止されているためです注8)。

メールの標準的に正しい方法はRFC 2231に則ったリスト5のような形式です。

リスト5 RFC 2231に則ったエンコード

Content-Disposition: attachment;
 filename*=UTF-8''%E3%81%82%E3%81%84%E3%81%86.txt

しかし,この「正しい」方法をサポートしていないメーラもあるため,歴史的に,前述の「正しくない」方法のほうが普及しています。

注8)
「5. Use of encoded-words in message headers」「An'encoded-word' MUST NOT appear within a 'quotedstring'」より。

著者プロフィール

高林哲(たかばやしさとる)

ソフトウェアエンジニア。バッドノウハウの研究,スルー力の探究,自転車置場の建設,Binary 2.0の布教などの活動を行っている。共著に『Binary Hacks』(オライリー 2006年)。ブログはhttp://0xcc.net/

著書

コメント

コメントの記入