XSS対策:JavaScriptのエスケープ(その3)
5/14の日記XSS対策:JavaScriptのエスケープ(その2) - ockeghem(徳丸浩)の日記に対して、id:hasegawayosukeさんからコメントを頂戴した。その内容は、JavaScriptに対応していないブラウザの場合に対する考慮が抜けているという趣旨だと理解した。
元の日記にも書いたように、私自身はJavaScriptの動的生成は(特殊な場合を除いて)好ましくないと考えているが、始めた以上は最後まで検討しようと思う。
解決すべき課題の整理
まず、解決すべき課題を整理しよう。元の日記では、JavaScriptを動的生成する(ただし、文字列リテラル内のデータに限る)場合のXSS対策として二段階のエスケープが必要であることを説明した。具体的には、(1)JavaScript文字列リテラルのエスケープとして、「"」、「'」、「\」のエスケープの実施、(2)HTMLとしてのエスケープである。
後者はさらに二種類に分かれる。イベントハンドラにおかれる場合は、属性値としての文字参照を実施する。<SCRIPT>タグ内の場合は文字参照が使えないので、文字列リテラル中の「</」をSCRPITタグの終端とブラウザに判断させないために、文字「/」を「\/」にエスケープすることを説明した。
上記(SCRIPTタグの方)は、JavaScriptに対応したブラウザの場合はうまく動作するが、JavaScriptに対応していないブラウザではうまくいかない。
そもそも、JavaScriptに対応しないブラウザには二種類がある。一つは、非常に古いブラウザや簡易的なブラウザなどSCRIPTタグそのものに対応していないもの、もう一つは、JavaScriptは実装されていないが、SCRIPTタグは認識して読み飛ばしを正しく行うものである。
つまり、三種類に分類されることになるが、それぞれの代表的なブラウザを下表にまとめた。
JavaScript対応 | SCRIPT対応 | SCRIPT非対応 |
---|---|---|
IE, Firefox, Operaなど多数 | Lynx、EZweb*1など | i-modeなど |
JavaScript非対応の代表的なブラウザとしてLynxがあるが、これもSCRIPTタグ(ないしNOSCRIPTタグ)には対応しているため、前述のJavaScriptのエスケープ問題はJavaScript対応のブラウザと同じように扱うことができる。つまり、HTMLアンエスケープのレイヤーではJavaScript対応ブラウザと同じ挙動を示すからである。言い換えると、LynxなどはJavaScriptの切り出しまでは行うが、実行はしないだけと考えるとわかりやすいかもしれない。
問題は、SCRIPTタグそのものを認識しないブラウザである。SCRIPTタグは、HTML4.0で正式に定義されてから10年近く経つことと、NOSCRIPTタグという代替手段も用意されているため、メジャーな非対応ブラウザは多くはない。どれがあったっけなと思い返していて最初に思いついたのがi-modeのブラウザである*2。
i-mode用などSCRIPTタグ非対応ブラウザが問題になる理由はこうだ。SCRIPTタグの内部では文字参照が使えない。このため、HTMLのタグ文字がそのまま(エスケープされずに)現れる。ところが、SCRIPTタグを認識しないブラウザは、スクリプトの内容をHTMLの一部として認識するからである。
これを防ぐために、SCRIPTタグの中身は、以下のようにHTMLコメントで囲むように推奨されている。
<SCRIPT TYPE="text/javascript"> <!-- var x = 1; ... //--> </SCRIPT>
やっと問題にたどり着いた。問題は、文字列リテラル内に「-->」という文字列が入る場合に、上記のHTMLコメントが終端となり、その後の文字列が画面表示されることになる。つまり、以下のようなスクリプトを動的生成されることによる問題である。
<SCRIPT TYPE="text/javascript"> <!-- ... var x = "-->●●●さまざまなタグなど"; ●●●以降が画面表示される ... //--> </SCRIPT>
問題が発生する条件
ここで問題が発生する条件を整理しよう
- サイト側でJavaScriptを動的生成している
- ユーザが<SCRIPT>タグ非対応のブラウザ(i-modeなど)を利用している
- (入力など)JavaScriptに挿入する文字列中に「-->」を含んである
起こりうる脅威
可能性として考えられる脅威は以下の通りである。
- 画面が乱れる
- テキストやタグの挿入により表示を改ざんされる
- AタグやFORMタグその他によりフィッシング的な攻撃をされる
現実には、3はほとんど発生し得ないと考えられる。なぜなら、「/」や「"」がJavaScrpit文字列リテラルのエスケープにより「\/」や「\"」に変更されるため、外部サイトへのURIを記述することが出来ないからである。一方、画面の乱れや改ざんはある程度可能であろう。
対応の必要性
この問題への対応要否は、上記の発生条件と脅威、加えて簡易ブラウザ(i-modeなど)の対応要否などからサイトごとに判断することになるだろう。
まとめ
JavaScriptのエスケープに対して、SCRIPTタグ非対応ブラウザの場合の問題点と脅威、対策について検討した。
対策は、JavaScriptの文字列リテラルのエスケープとして、以下の変換を行うことである。
対象文字 | 変換後文字列 |
---|---|
' | \' |
" | \" |
\ | \\ |
/ | \/ |
> | \x3e |
ただし、何度も触れているように、JavaScriptの動的生成は推奨していない。hidden fieldに値を入れておいてJavaScriptから参照する方が安全であるし、それほどコード量が増えるわけでもない。
おまけ
脆弱性診断をやっていると、JavaScriptの動的生成箇所でXSS脆弱性が発生しているケースを少なからず見かける。ご注意を。