本当は怖い文字コードの話

第1回UTF-7によるクロスサイトスクリプティング攻撃[前編]

みなさん、はじめまして。はせがわようすけと申します。

最近、文字コードと関連したセキュリティの話題を目にすることが増えてきました。文字コードを利用した攻撃は技術的に未開拓ということもあり、参考となる情報がなかなか見当たりません。この連載では、文字コードを利用した攻撃やそれに対する対策について正しい知識を解説していきます。

文字コードとセキュリティが関連するもっとも大きな点は、やはり文字列の比較でしょう。⁠危険な文字列の検出」⁠安全な文字列であることの確認」といった文字列の比較は、セキュリティを考えるうえで避けて通れない処理だと思います。

文字列の比較においては、単純にバイト列を比較するだけでは不十分で、文字列がメモリ上でどのようなバイト列として格納されているのか(このルールを符号化方式あるいは文字エンコーディングと言います)に注意しなければならないこともあるでしょう。攻撃者は巧みに文字コードを操ることにより、文字列の比較処理において本来不一致であるものを一致させ、あるいは検出されるべき文字列をかいくぐるといったことが可能になります。

また、文字コードを利用したトリックは、比較の一致・不一致といったソフトウェアの処理上の問題だけでなく、人間に対する視覚的な効果という点でも強く影響を与え、攻撃者にとっての強力な道具となり得ます。

こういった、文字コードが引き起こすセキュリティ上の問題について近年特に目にする機会が増えてきた背景には、もちろんWebアプリケーションの著しい成長があると思います。WebブラウザはHTMLやXMLをはじめとするテキストデータを大量に扱う巨大なテキストパーサであり、データを適切に解釈するために文字コードは重要な位置を占めていますので、文字コードに関する処理が適切でない場合にはセキュリティ上の問題に直結することも多々あります。

また、Webアプリケーション以外のローカル環境上で動くアプリケーションであっても、EUC-JPやShift_JISといったレガシーなエンコーディングからUnicodeへ遷移している現状において様々な混乱が生まれ、場合によってはセキュリティ上の問題を引き起こすこともあります。

このような背景事情を踏まえ、今回および次回でUTF-7によるクロスサイトスクリプティング(XSS)という話題について説明したいと思います。UTF-7によるXSSの話題は、Webアプリケーションのセキュリティに関わっている方なら一度は聞いたことがあるかと思いますが、まだまだきちんとした解説は少ないようですので、この記事を読んだ人にはUTF-7によるXSSは二度と発生させない、というくらいの意気込みで徹底的に説明しておきたいと思います。

UTF-7を利用したXSS

結論を先に書いてしまうと、UTF-7を利用したXSSは、HTTPレスポンスヘッダにて

Content-Type: text/html; charset=UTF-8

Content-Type: text/html; charset=Shift_JIS

Content-Type: text/html; charset=EUC-JP

のいずれかを出力することで完全に防ぐことができます。

もちろん、これ以外にもUTF-7によるXSSが発生しない条件は多々ありますが、できる限りシンプルで覚えやすいルールということで、⁠レスポンスヘッダで」⁠この3種類のcharsetのいずれかを指示」の2つの条件を覚えておいてください。

では、これがなぜ完全な対策になるのか、そもそもUTF-7によるXSSはどのようなときに発生するのかを詳細に説明していきます。

UTF-7とは

UTF-7は符号化方式のひとつで、Unicodeのすべての文字を7ビットで表現できます。もともとメール環境での利用が想定されていましたが、現在のUnicode規格からはすでに削除されています。また、RFC2152においてUTF-7の符号化方法が定められていますが、このRFC2152においても

This memo provides information for the Internet community.  This memo
does not specify an Internet standard of any kind.  

と明記されており、UTF-7という符号化方式は現在は標準的には利用されていません。

すべての文字を7ビットで表すために、英数字と一部の記号を除き、base64をもとにした方法で各文字が符号化されます。たとえば、

<div> XSSが好き </div>

という文字列をUTF-7で表すと

+ADw-div+AD4- XSS+MExZfTBN- +ADw-/div+AD4-

に、

<script> alert("xss") </script>

という文字列をUTF-7で表すと

+ADw-script+AD4- alert(+ACI-xss+ACI-) +ADw-/script+AD4-

のようになります。

このように、UTF-7では「<」⁠>」⁠"」といったメタキャラクタを直接記述せずにそれらの文字を表すことができます。

UTF-7によるXSSが発生するメカニズム

UTF-7によるXSSは、文字エンコーディング(charset)が不明瞭なWebアプリケーションをInternet Explorerで閲覧している際に攻撃対象となります。文字エンコーディングが不明瞭なWebアプリケーションにおいて、先に示したように「+ADw-script+AD4-」のような文字列を生成させておき、その状態でIEに「このHTMLはUTF-7である」と認識させることでXSS攻撃が成立します。

Webアプリケーション上では「<」⁠>」などを正しくエスケープしているにもかかわらず、ブラウザ側で「<」⁠>」と同じ意味を持つバイト列を挿入するという、まさに冒頭で述べたような「比較検出のすり抜け」が行われているのです。

さて、⁠文字エンコーディングが不明瞭」とは具体的にどのような状況なのかというと、以下のような条件のいずれかに該当するときです。

  • レスポンスヘッダ、meta要素のどちらでもcharsetが指定されていない
  • charsetにIEが解釈できないエンコーディング名が指定されている
  • meta要素でcharsetを指定しているときに、meta要素より前に攻撃者が文字列を挿入可能

このようなWebアプリケーションでは、攻撃者はIEに文字エンコーディングをUTF-7であると誤認させることができますので、XSSが成立してしまいます。

次回以降で、UTF-7によるXSSが発生するメカニズムについて引き続き説明していきます。

おすすめ記事

記事・ニュース一覧