遅ればせながらIE8β2のAnti-XSS機能(の一部)である、XSS FilterとtoStaticHTMLを触ってみました。その感触を少し書いてみます。
XSS Filter
一般論として、XSSの攻撃や対策方法は、パラメータの値がHTMLのどの部分に出力されるかによって異なります。
① タグの内側(Element Content) 例:<p>ここ</p> ② 通常の属性値内(クォート付き) 例:<input type="text" name="foo" value="ここ"> ③ JavaScriptの文字列リテラル内 例:<script>var x='ここ';</script> ④ URI属性値内 例:<a href="ここ">
上記以外のパターンもありますが、実際のWebアプリで多く見られるのは上のようなパターンではないかと思います。
ちょっと触ってみた感じでいうと、XSS Filterは上記の①〜④の全てに対応している(対応しようとしている)ようです。
今回は、もっともオーソドックスな①のパターンについて突破を試みました。
思ったよりも難敵でしたが、いくつか突破する方法もありましたので以下に書いてみます。
2つのパラメータの合せ技
例えばx,yという二つのパラメータの値がHTMLに出力されるとします。このうちパラメータxがエスケープされておらず、XSSに脆弱だとします。
この場合、以下のようなパラメータを送るとFilterを突破できます。
x=<img/style=`/* y=*/x:expression(alert(123))`
ただし、XSS成功にはいくつかの条件があります。例えば、HTMLの中で、パラメータxはyよりも先頭の方に出力されなければなりません。
この「合せ技」は、攻撃方法としてはある意味で"邪道"ではありますが、実際的な攻撃方法だと思います。
文字コード系
文字コード系は、既にいくつか突破する方法が発見されています。
続: Internet Explorer の XSS Filter - 葉っぱ日記
http://www.80sec.com/ie8-xssfilter-bypass.html
ですので、少し目先を変えてみました。
A. PHP/ASP x=<scr%C0ipt>alert(123)</script> B. Java x=%C0%BCscript>alert(123)</script>
いずれも、UTF-8環境で動作するものです。
上のAの仕組みは単純です。UTF-8として不正な文字断片である%C0がサーバ側で除去されて「<script>alert(123)</script>」がレスポンスされるために動作します。
私の環境では、ASP、PHPにて文字コードをUTF-8に設定したところ、アプリのコードでは特に何もしなくても%C0が除去されてレスポンスされました。ただしPHP環境に関しては、少なくともmbstring.encoding_translationをOnにしない限り、%C0は除去されないと思います。
Bは、いわゆるUTF-8のoverlong sequenceを利用しています(この問題はいつまでたっても直されないようです)。%C0%BCはサーバ側(Java)で「<」に変換されてレスポンスされます。
上の2つはともに、パラメータがそのままレスポンスされるのならばXSSには至らないために、XSS Filterは素通りさせてしまうのだと思います。しかし、サーバ側のアプリケーション実行環境のパラメータ処理によって、上のA,Bのように微妙に元の値とは異なる値がレスポンスされることがあります。
その他
IE8のXSS Filter(の回避方法)に興味がある方は、以下の記事も参考になります。
Web Security Research» Alex's Corner: IE8 XSS Filter
http://blogs.technet.com/swi/archive/2008/08/18/ie-8-xss-filter-architecture-implementation.aspx
これらの記事で扱っているのは、全く違うアプローチでのFilterの回避方法です。かいつまんで言うと、XSS Filterは同一ドメインでのページ遷移では機能しないように設計されているのですが、この設計を利用してFilterを回避する方法です。
toStaticHTML
toStaticHTMLは、HTML断片からJavaScriptを除去してくれる、JavaScriptの関数です。
ブラウザ側でJavaScript除去処理を行なう事のアドバンテージは、除去処理においてブラウザのHTML/CSS Parserが使えることです。ブラウザに備わっているParserを使用して、ブラウザがHTMLを解釈するのと同じ方法でHTMLを解釈した上でJavaScriptの除去処理を行なえば、高い精度の処理ができるはずです。
・・・と思って試してみた訳ですが、期待していたものとは違いました。
toStaticHTML関数に少し変わったHTMLを与えて出力を見ると、IEが備えるParserとは違う解釈をしていることが判ります。
例えば、以下のようなHTMLを与えます。
(toStaticHTMLへの入力) <img src=1[0x0B]alt=2 id=`3`> (toStaticHTMLからの戻り値) <img src="1alt=2" id="`3`">
判りにくいですが、入力の「<img」と「src」の間のスペースは全角スペースです。戻り値を見ると、toStaticHTMLがこの全角スペースを半角スペースと同等に扱っていることが判ります。
また、src属性とalt属性はU+000B(垂直タブ)で区切っています。IEネイティブのParserは、U+000Bを属性の区切りとして扱いますが、toStaticHTML関数はこれを区切りとは認識しません。さらに、バッククォートの扱いにもIEネイティブのParserとの差が見られます。
同様に、CSSの解釈方法(トークンの切り出しなど)にも違いが見られました。
どうやら、toStaticHTML関数は、IEに元々備わっているHTMLやCSSのParserではなく、この関数独自のParserでHTML/CSSを解析して、JavaScriptの除去処理を行なっているようです。
独自Parserを使っていたとしても、安全なフィルタ処理がされているのであればそれでよいのですが、試したみたところそうではないようです。特にCSSの処理がいまいちで、style属性がついたHTMLを使うと、割と簡単にXSSできてしまいました。
CSSの文法はややこしいので、あえて独自Parserなど使わない方がいいのに・・・というのが私の感想です。