jQueryの落とし穴
2011年6月24日(金曜日)
jQueryの落とし穴
公開: 2011年7月3日19時35分頃
「jQueryにおけるXSSを引き起こしやすい問題について (subtech.g.hatena.ne.jp)」。これは非常に興味深いお話ですね。
jQuery (jquery.com)はJavaScriptのライブラリですが、最近ではもうほとんどのサイトで使われていると言っても過言ではないくらい使われています。これは非常に便利で、面倒なDOM操作をとても簡単に書くことができます。たとえばこんな感じです。
$(function(){ $('#main-contents>div').append($('<p>こんにちは</p>')) });
上記のようなコードは良くあるのですが、よく見ると、$() は渡されたものの種類によって全く違う動作をしている事が分かります。
- functionを渡すと、DOM読み込み可能になったタイミング (DOMReady) でそのfunctionを実行
- CSSのセレクタのような文字列を渡すと、既存のノードを選択する動作 (getElementByIdやgetElementsByTagNameのような処理)
- タグのような文字列を渡すと、新たに要素を生成する動作 (createElementのような処理)
この他に、DOMのノードを渡すとjQueryオブジェクトに変換する機能もあります。
ポイントは文字列を渡したときの動作が2種類あることで、しかも、それぞれが全く違う動作になります。そのため、既存のノードを選択しようと思っていたのに要素が作られてしまうということが起こり得ます。
jQuery1.6.1のソースコードを見ると、以下のような正規表現にマッチした場合に要素作成になるようです。
quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
先頭のほうに [^<]* があるのがポイントで、開始タグの前に任意の文字列が存在していても良いことになっています。'#foo-bar<tag>' のような文字列はこれにマッチしますので、要素が作成されることになります。
script要素が作られても、それがDOMツリーに挿入されなければ問題ない……と思うかもしれませんが、onerrorイベント付きのimg要素を作らせるような技があり、挿入されなくてもスクリプトを実行させることができてしまいます。これがXSSの原因になり得る、というのが今回のお話です。
$() が万能というのはjQueryの設計思想なのだと思いますが、型が同じ (文字列型の) 引数を渡しているのに挙動が全く違うというのは、予期せぬところで問題を引き起こしやすいだろうとは思います。
- 「jQueryの落とし穴」にコメントを書く
関連する話題: Web / セキュリティ / JavaScript
- 前(古い): Movable Typeまたまたアップデート (詳細不明)
- 次(新しい): ログ解析で攻撃に気付くのは簡単?