最近、徳丸本をじわじわ読んでいるのですが、DOM based XSSの話が書いてあったので、少し言及しておこうと思います。
徳丸本から引用
DOM based XSSと呼ばれるXSSがあります。これは、JavaScriptによりクライアント側で表示処理する箇所があり、そこに脆弱性がある場合のXSSです。
サンプル書いてみました。
<script> document.write(unescape(location.href)); </script>
こいつを適当なファイル名で保存して、domxss.html#<script>alert("hello")<script>などのURLでアクセスするとalertが表示されるはずです。任意のスクリプトが実行可能な状態ってことですね。任意のスクリプトが実行可能ってことは、セッションクッキー盗み放題で、他人に成り済まして買い物できちゃったりするレベルです。
悪いのはdocument.write()やinnerHTMLだ
例はかなりわざとらしいですが、document.write()やinnerHTMLといった、文字そのままを書き出すメソッドやプロパティを使うと、そこにDOM based XSSが可能になる余地が生まれます。
対策としてはhtmlをエスケープする、ちゃんとしたテンプレートエンジンを使う、ウェブ標準のDOM APIを使うなどが挙げられます。
DOMを使った対策例
DOMのAPIは適切なエスケープ処理を自動で行ってくれるため、XSSの対策になります。たとえばさっきの脆弱なコードはこんな風に書けばOK。
<script> onload=function(){ document.body.appendChild(document.createTextNode(location.href)); }; </script>
しかしinnerHTMLの方が人気者?
「DOM vs innerHTML」でググると、パフォーマンスを比較する記事がたくさん見つかります。なかなか比較するのは難しいけれど、単純な性能で言えばinnerHTMLの方が速い傾向にあるらしいですね。
あとDOMのAPIは面倒くさいことが多いです。document.createElement()とかappendChild()しまくるよりは、innerHTMLで文字列連結しちゃった方が楽かもしれない。
なので、第三者の入力を受け付ける部分だけちゃんとDOMで書いて、外部入力の入り込む余地のない部分だけinnerHTMLで書く、ぐらいがよいと思います。
ただ、、、こういうinnerHTMLをばりばり使った記事が、未だに人気を集めるところを見ると、「DOMの書き換えはinnerHTMLを使って書くものなんですね!メモメモ〜☆」みたいな勘違いをする人が多そうで、今の状況は良くない気がしています。
言いたいこと
- DOM APIとinnerHTMLは等価ではない。パフォーマンスだけで比較するのはナンセンス。
- innerHTMLは危険な書き方である。何でもかんでもinnerHTMLを使うのはやめた方がいい。
- JavaScriptにだってXSSを作り込む可能性がある。DOM based XSSはもう少し周知されるべき
もっと詳しく知りたい人は
DOM based XSSはここがかなり詳しい。英語だけど。
DOM based XSS Prevention Cheat Sheet - OWASP
冒頭の徳丸本ってのはこれのことね。サーバーサイドの話が多いけど、Web屋さんは知っておくべき内容。(DOM based XSSはp115の辺り)
体系的に学ぶ 安全なWebアプリケーションの作り方 脆弱性が生まれる原理と対策の実践 [大型本] / 徳丸 浩 (著); ソフトバンククリエイティブ (刊)
ハイパフォーマンスJavaScriptにDOMとinnerHTMLの速度比較の記事が載ってた。(p37 3章のあたり)
ハイパフォーマンスJavaScript [大型本] / Nicholas C. Zakas (著); 水野 貴明 (翻訳); オライリージャパン (刊)
innerHTMLを使わないDOMの参考図書。「DOM Scripting」的な名前の本ならあまりハズレはない気がする。私はこれで勉強しましたが、他にもいい本があるかもしれない。
Web標準テキスト(1) DOM Scripting (Web標準テキストシリーズ) [単行本(ソフトカバー)] / 古籏 一浩 (著); 技術評論社 (刊)
keyword: javascript Security