JavaScriptのエスケープを意識する箇所:
a. document.write(...); b. jQuery : $('#id').text(...); c. jQuery : $('#id').html(...); d. JSON : { "key" : "..." }
まだまとめきれてません:
参考:
document.write()は最近見かけなくなったとはいえ、jQueryの場合だけでも、正直頭が痛くなってきます。
$('#id').text('<?php echo htmlspecialchars($_GET['data'], ENT_QUOTES); ?>');
とすると二重エスケープになってしまいます。なので
$('#id').text('<?php echo $_GET['data']; ?>');
としてしまいますと、"</script>"などの閉じタグが入り込んでしまうとブロックが閉じてしまいます。
結果、
$('#id').html('<?php echo htmlspecialchars($_GET['data'], ENT_QUOTES); ?>');
としないと安心できません(=安全、と断言できるレベルではまだ無い)。
しかしそうなってくると、そもそもjQueryのhtml()でHTMLブロックをごそっと突っ込む機能自体が要らないのではないか、という気もしてきます。
つまり入力に含まれるHTMLタグは、エスケープされて表示されるべきということを徹底し、HTML要素を組み立てる必要があれば、DOM要素を1つずつ組み立てていく方が安心できます。とはいえ、過剰エスケープを抑制するためにわざわざ「エスケープをしない」jQuery.html()を使う、というのも混乱を招きそうです。
hiddenタグに出力してそれを参照すれば、少しわかりやすくなります。
<?php function h($s) { echo htmlspecialchars($s, ENT_QUOTES); } ?> <html> <head> <title>jQuery Escape Test</title> <script type="text/javascript" src="../jquery-1.6.1.min.js"></script> </head> <body> <div id="msg">dummy</div> <input type="button" value="act1" onclick="act1()" /> <input type="button" value="act2" onclick="act2()" /> <input type="hidden" name="data" id="data" value="<?php h('<b>bold</b>'); ?>" /> <script type="text/javascript"> function act1() { $('#msg').text($('#data').val()); } function act2() { $('#msg').html($('#data').val()); } </script> </body> </html>
これならばjQuery.text()で過剰エスケープはされませんでした。jQuery.html()ではちゃんと<b>が効いて太字になってくれます。
ユーザ入力を(なんのチェックも無しに)jQuery.html()に渡すことは無いと思いますので("<script>とか含まれてたら動いてしまう)、hiddenに出力してjQuery.text()で出力、という方式は比較的安定していると思います。エスケープを考慮するレイヤーがHTMLレイヤーだけにとどまり、JavaScriptの構文解析レイヤーを気にしなくて良いのでわかりやすいです。
コメント