脆弱性"&'<<>\ Advent Calendar 2015 最終日の記事です。今年も無事全て埋まりました。ご協力ありがとうございました。
最終日だからといって特に面白いネタがあるわけでもないので、普通に書く。
一般的に、HTML中に外部から与えられる文字列を埋め込む場合は、<
, >
, "
, '
, &
をエスケープすれば良い。このうち&
については、エスケープしないと不具合になるが、脆弱性とはならない。ユーザーがpaste©
と入力するとpaste©
になってしまうが、これを悪用して何かができるわけではない。
<a href=url>
のurl
の部分にユーザーの入力を埋め込む場合がこれの例外となる。javascript:alert(location)
というURLを指定され、ページの閲覧者がこのリンクをクリックすると、サイトのオリジンでスクリプトが動作する。ブラックリストでjavascript:
を弾くという対処をしていた場合、&
のエスケープを忘れていると、javascript:
というように文字参照を利用することで回避されてしまう。
ガルーンのリンクがこれに近い状態だった。&
のエスケープがなされておらず、http:
とhttps:
以外でコロンが含まれていればリンクが削除されるようだった。ただし、ちゃんと文字参照を解釈していたので、単純にjavascript:alert(location)
を指定するだけでは弾かれた。しかし、ガルーンのリンクは空白を削除するという処理が行われていて、例えば、http:// example .com
はhttp://example.com
となる。この空白の削除が、悪意のあるリンク先を弾く処理の後というのが脆弱性だった。
POC: javascript& #x3a;alert(location)
安全なWebアプリケーションの作り方によると、URLに指定する文字列をhttp://
, https://
, /
のいずれかから始まるもののみに限定して、HTMLエスケープをすれば良いらしい。このように実装するのが確実だが、ガルーンの場合は今でも&
がエスケープされていないし、(:
が含まれていなければ)http://
から始まらないURLを設定することもできる。理由は推測するしかないけれども、&
をエスケープすると古いブラウザで不具合があるとか、ガルーン内への相対リンクを指定できると便利だったりとかだろうか?
この状態でこの脆弱性を防ぐのはとても大変。:
を弾くだけではもちろんダメで、:
のように10進数にしたり、:
のように0を追加したりするという手がある。もしかしたら、&#b111010;
のような2進数を解釈したり、:
のような実体参照が使えるブラウザがあるかもしれない。でも、脆弱性報奨金制度でさんざん突っつかれているだろうから、今さらこのような穴は残っていないはず。そう考えると、危険だけれども便利という方法を取れるのは、脆弱性報奨金制度を実施しているからこそかもしれない。
ちなみに、この脆弱性で他人を攻撃できる私が見つけた経路は、管理者しか追加できない共有リンクと、RSSリーダー機能で読み込ませる必要があるRSS中のリンク。さらに、ページを開くだけではなく、リンクをクリックさせないと発動しない。攻撃が難しいというのも危うい対策を取れる理由なのかもしれない。