読者です 読者をやめる 読者になる 読者になる

素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: すかいぷ:javascripter_  か javascripter あっと tsukkun.net skypeのほうがいいです

シングルクォートもきちんとエスケープする

追記2:2007-10-11 - hoshikuzu | star_dust の書斎を見ると、下に書いてるような対策では不十分なようだ。
追記:エスケープすべき文字は、Re: JavaScript内(文字列)にデータを出力する場合の適切なエスケープ手順|freeml byGMOなどを参考に。

シングルクォート(')をエスケープせずXSSの原因になっているサイトをけっこう見かけたので、どういう時問題になるのか書いておく。
JavaScriptの文字列を動的に埋め込む場合。

<script>
var q = 'hoge&quot;fuga';
document.getElementById('word').appendChild(document.createTextNode(q + 'の検索結果'));
</script>

のように、変数に代入する文字列を動的に作っている場合、RubyのCGI.escapeHTMLとか、PHPのhtmlspecialcharsとかを使うべきではない。
script要素の中身はHTMLではなくJavaScriptだから、JavaScriptの文字列用にエスケープするメソッドを使う必要がある。
シングルクォートをエスケープしていない場合、クエリに?q="'<を投げたら、

<script>
var q = '&quot;'&lt;';
document.getElementById('word').appendChild(document.createTextNode(q + 'の検索結果'));
</script>

のようになって、'&quot;'の部分で文字列が分断されてしまう。?q=';alert('XSS');'のようなクエリを投げられた場合、

<script>
var q = '';alert('XSS');'';
document.getElementById('word').appendChild(document.createTextNode(q + 'の検索結果'));
</script>

のように、JavaScriptを挿入されてしまう。
出力時エスケープの原則に従う場合、?q='"<を投げた場合、

<script>
var q = '\'"<';
document.getElementById('word').appendChild(document.createTextNode(q + 'の検索結果'));
</script>

のような結果になるべき。エスケープすべき文字列は、文字列を囲っている物が"の場合、'の場合で異なる。
'で囲っている場合は、'を\'に、\を\\にする。XHTMLを使っている場合、

]]>

という文字列があった時点でCDATAセクションの終了になるので、

']]' + '>'

のように変換されるようにするなど、特別な配慮が必要。

大きいサイトでもこういうXSSがあったりするので、見つけたら404 Not Foundに報告しましょう。