[これはひどい]IEの引用符の解釈:教科書に載らないWebアプリケーションセキュリティ(1)(3/3 ページ)
XSSにCSRFにSQLインジェクションにディレクトリトラバーサル……Webアプリケーションのプログラマが知っておくべき脆弱性はいっぱいあります。そこで本連載では、そのようなメジャーなもの“以外”も掘り下げていきます(編集部)
セキュリティ上の問題
さて、このバッククオーテーションの扱いがセキュリティに及ぼす影響ですが、典型的には次のようなコードの場合に問題が発生します。
<div id="div1"> <input type="text" value="ここに攻撃者の指定した文字列が挿入可能"> …… (1) </div> <div id="div2"> </div> <script> document.getElementById( "div2" ).innerHTML = document.getElementById( "div1" ).innerHTML; …… (2) </script>
Webアプリケーション側で生成したHTMLの一部を、JavaScriptのinnerHTMLを利用して複製しています。このとき、例えば攻撃者がvalue属性に「``onmouseover=alert(1)」のような文字列を挿入すると、div1のinnerHTMLを取得している部分(2)では属性値を囲む引用符が取り払われ、結果的に生成されるHTMLは、
<div id="div1"> <input type="text" value="``onmouseover=alert(1)"> </div> <div id="div2"> <input type="text" value=``onmouseover=alert(1)> </div>
のようになり、div2の中にあるinput要素ではvalue属性が空に、onmouseoverイベントハンドラが有効になりますので、攻撃者によるXSSが成立してしまいます。
ここではinnerHTMLを例に挙げていますが、outerHTMLを使用した場合でも同様の問題が発生します。ただし、outerHTMLはWebブラウザ間の互換性の問題からinnerHTMLほど積極的には使われていませんので、問題が顕在化することも少ないでしょう。
誤解していただきたくないのは、「攻撃者のコードを含むinnerHTMLのコピーはHTMLの出力に相当する。エスケープしてコピーしていないのが悪い」というのではない点です。
HTML生成時に必要なエスケープは(1)の部分を生成する時点で完了しており、innerHTMLのコピーではコピー元とコピー先のDOM構造は一致するべきで、この例のようにDOM構造がコピー前後で異なってしまうというのは、理解しがたい挙動なのです。
さて、対策としては残念ながら「HTMLを生成時にエスケープする」のような簡単な方法はありませんので、innerHTMLの複製には直接innerHTMLをコピーするのではなく、cloneNodeを使って回避するという手段を採ります。
var src = document.getElementById( "div1" ); var dst = document.getElementById( "div2" ); var nodes = src.childNodes; for( var i = 0; i < nodes.length; i++ ){ dst.appendChild( nodes[ i ].cloneNode( true ) ); }
このようなコードを書くことで、innerHTMLのコピーと等価であり、なおかつコピーの前後でDOM構造を壊さずに複製を作ることができますが、なんとも収まりの悪い気がします。
なお、余談ですが、IEの「バッククオーテーションを中途半端に引用符として扱う」というこの挙動に関して、最も影響を受けるのはおそらく印刷のときでしょう。どのようなサイトでも結構ですので、検索語などのテキストボックスにバッククオーテーションを1文字「`」とだけ入力して、印刷プレビューを表示してみると表示がおかしくなっていることを確認できると思います。
これは脆弱性ではないのか
さて、このIEの挙動についてですが、脆弱性とはいわないまでもセキュリティ上好ましくない挙動であるので修正されるべきではないかと私は考えました。
2008年10月ごろのことですが、ちょうどIE 8のベータ版に関してフィードバックを募集していましたので、この件についてレポートを提出しました。ところが、その返事は残念ながら「よいフィードバックだが、Backward Compatibilityのためにバッククオーテーションによる引用符をサポートし続ける。属性値として出力する場合には、ダブルクオーテーションやシングルクオーテーションで囲むという回避策をとってほしい」というものでした。
事実、2009年1月末にダウンロードが開始されたIE 8 RC1(8.0.6001.18372)においてもこの問題は解決されていませんでした。ダブルクオーテーションやシングルクオーテーションでくくることが回避方法にならないのは上で示したとおりであり、フィードバックとしてうまく伝えきれなかったという悔恨の残るものになってしまいました。
マイクロソフトの実装にはひどいところも多いと思いますが、それでも改善を主張する声が集まれば、決してそれを無視する会社ではないと信じています。この記事を読んで、IEのこの仕様について「これはひどい」と思った方がもしおられましたら、ぜひ一緒に声を上げてほしいと思います。
Copyright © ITmedia, Inc. All Rights Reserved.