XSSに関する最後の問題。
問題6. Reflected XSS via AJAX
調査
6問目は「Find a URL that when clicked on will execute a script using one of Jarlsberg’s AJAX features.」。AJAXのバグを突くことにより、ユーザーにURLをクリックさせることで任意のscriptを実行させることができるか。
ajaxを使っている機能を、先ほどのHome画面以外で探す。My Snippets画面にもRefresh機能がある。ここでもAjaxを使っている。該当のコードは以下の通り。
<div class='refresh'><a class='button' onclick='_refreshSnippets("xxxxxxxxx", "golem-xiv")' href='#'>Refresh</a></div>
function _refreshSnippets(uniqueId, uid) { _refresh("/" + uniqueId + "/feed.jtl?uid=" + uid, _finishRefreshSnippets); };
“http://127.0.0.1:8008/xxxxxxx/feed.jtl?uid=golem-xiv”というHTTPリクエストが発行されると、以下のようなレスポンスが返ってくることになる。
_feed(( [ "golem-xiv" ,"Hello, Secure World!" ] ))
つまり、ユーザー名の場所に、任意の文字列を埋め込むことが可能だ。
脆弱性の確認
以下のURLを踏ませることで、スクリプトを実行させることが可能。*1
http://127.0.0.1:8008/2061610856/feed.jtl?uid=<script>alert(document.cookie)</script>
これは、上記URLのレスポンスが以下のような形式で返され、また、content-typeがtext/htmlとなっていることが原因。ブラウザはレスポンスをHTMLとして解釈してしまい、スクリプトが実行される。
_feed(( [ "<script>alert(document.cookie)</script>" ] ))
HTTPのヘッダは、以下のとおりとなっており、確かにcontent-typeがtext/htmlとなっている。
対策
- エスケープ処理
- javascriptの文字列中で<、>を使う場合は、エスケープ処理を行う。各々\x3c、\x3eにエスケープしてやる。
- 正しいContent-Typeをセットする
- レスポンスがHTMLとして解釈されないように、Content-Typeをセットする。RFC4627によれば、JSONのMIME typeはapplication/jsonのようだ。*2jarlsbergのドキュメントでは、application/javascriptを使う、となっている。うーん、どっちが正しいのかな。ただ、jarlsbergのドキュメントによると、ブラウザによっては、content-typeを無視して解釈しようとしてしまうこともあるので、正しいcontent-typeを使うようにする対応だけでは不十分、とのことだ。
- 正しいエンコード(charset)をセットする
- さらに、Jarlsbergのドキュメントによれば、正しいcharsetをセットすることも必要とのこと。もし攻撃者が、何らかの方法でレスポンスのcharsetをUTF7だとブラウザに誤認させることができたとする。すると、+ADw-script+AD4- を<script>に解釈させることが可能(+ADw-と+AD4-は、UTF7で各々<と>に該当する)。IEに依存したWebアプリケーションセキュリティに詳しい説明があった。: