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

第3回US-ASCIIによるクロスサイトスクリプティング

今回は、US-ASCIIによるクロスサイトスクリプティング(XSS)という話題について紹介します。

前回までで説明したUTF-7によるXSSと同様に、攻撃者はUS-ASCIIという文字コードを巧みに利用することで、IEを対象にXSSを発生させることができます。US-ASCIIによるXSSは、UTF-7によるXSSと類似点も多いため、前回までの説明も併せて読んでおくとよいでしょう。

US-ASCIIによるXSSについても先に対策を書いてしまうと、UTF-7のときと同様にHTTPレスポンスヘッダにて

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

のいずれかを出力するという原則を守ることで、完全に攻撃を防ぐことができます。

US-ASCIIによるXSSが発生するメカニズム

US-ASCIIとは、みなさんもご存じのとおり、7ビットで英数字と少数の記号を表現する文字コードで、0x00から0x7Fまでの128種類の文字を扱うことができます。US-ASCIIで記述されたコンテンツをInternet Explorerで開いたときには、0x00から0x7Fの128文字を解釈するだけでなく、0x80から0xFFまでの7ビットにおさまらない範囲の文字について、最上位ビットが無視され0x00から0xFFと等価と解釈されます。

たとえば、⁠A」⁠B」⁠C」という文字はUS-ASCIIではそれぞれ0x41、0x42、0x43と規定されていますが、Internet Explorerではそれらの最上位ビットを1にセットした0xC1、0xC2、0xC3の各バイト値についても、0x41、0x42、0x43と同様に「A」⁠B」⁠C」と解釈します表1⁠。

表1 Internet Explolerが「A」⁠B」⁠C」と解釈するバイト値
 
US-ASCII
最上位ビットを1にセット
文字16進2進16進2進
A0x41010000010xC111000001
B0x42010000100xC211000010
C0x43010000110xC311000011

同様に、0xA2、0xBC、0XBEの各バイト値は、0x22、0x3C、0x3E、すなわち「"」⁠<」⁠>」と等価であると解釈されます表2⁠。

表2 Internet Explolerが「"」⁠<」⁠>」と解釈するバイト値
 
US-ASCII
最上位ビットを1にセット
文字16進2進16進2進
"0x22001000100xA210100010
<0x3C001111000xBC10111100
>0x3E001111100xBE10111110

Webアプリケーション側では通常は「"」⁠<」⁠>」といった文字を対象に、HTML生成時にエスケープすることでXSSを防いでいますが、US-ASCIIでは0xA2、0xBC、0XBEといったエスケープ対象ではない各バイト値がブラウザ上で 0x22、0x3C、0x3Eつまり「"」⁠<」⁠>」と等価と解釈されるため、XSSが成立してしまいます。

たとえば、リスト1のようなHTMLファイルをメモ帳などで作成し、文字エンコーディングにShift_JIS(メモ帳の場合は文字コードをANSIにします)として保存します。

リスト1 US-ASCIIで半角カナが入ったHTML
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=us-ascii">
</head>
<body>
シscriptセalert(document.charset)シ/scriptセ
</body>
</html>

半角カタカナの「シ」⁠セ」は、Shift_JISでは0xBC、0xBEです。このファイルをInternet Explorerで開いた場合には、HTMLはUS-ASCIIと解釈されるため、それぞれ0x3C、0x3Eつまり「<」⁠>」となり、図1のようにスクリプトが動作します。

図1 リスト1のファイルをIEで開いた結果
図1 リスト1のファイルをIEで開いた結果

攻撃対象となるWebアプリケーション

IEのUS-ASCIIの解釈を悪用したXSSが成立するWebアプリケーションとしては、

  • 明示的に文字エンコーディング名としてUS-ASCIIを指定している
  • 文字エンコーディングが不明瞭

のいずれかが対象となります。

UTF-7によるXSSの場合、明示的に「charset=UTF-7」のように指定しているWebアプリケーションというのは現実的にはほとんど存在しませんでしたが、⁠charset=US-ASCII」という明示的な指定は、英語でのページやエラーメッセージなどで見かけることがあります。

特に、Webアプリケーションの開発側として明示的にUS-ASCIIを指定しているつもりはなくても、404応答などのエラーページにおいてUS-ASCIIが使われている場合もありますので注意が必要です。

また、明示的にUS-ASCIIを指定していない場合でも、⁠文字エンコーディングが不明瞭」なWebアプリケーションでは、UTF-7によるXSSと同様に、IEにとって「コンテンツがUS-ASCIIである」と判断させることでXSSが発生することがあります。

まとめ

このように、明示的に文字エンコーディングを指定している場合でも、US-ASCIIの場合にはIEの過剰なまでのHTMLの解釈によって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

のいずれかをHTTPレスポンスヘッダに出力する、というのをルールとして徹底することを強くお勧めします。

おすすめ記事

記事・ニュース一覧