PHPで呼び出した文字列内の特殊文字で、JavaScriptエラーが出る場合の対処法

例えばPHPにてデータベースに入っている文字列を呼び出して、その文字列をJavaScriptで使おうとした際に、「’」シングルクォーテーションや「”」ダブルクオーテーションなどが入っていると、上手く動作しないことがあります。
例えば、JavaScriptの変数にvar a=[“<? echo $data[0]; ?>”,”<? echo $data[1]; ?>”];のようにしていた場合、$data[0]の中にダブルクオーテーションがあれば、動きません。こんな時は、あらかじめPHP側でHTMLエンティティに変換すると解決します。
$data[0]=preg_replace("/&/","&",$data[0]); $data[0]=preg_replace("/'/","'",$data[0]); $data[0]=preg_replace("/"/",""",$data[0]);
2013/3/4追記
セキュリティコンサルトの徳丸さんより、XSSのご指摘をいただきました。ありがとうございます。
コメントしましたが、 </script><script>alert(/1/)// でXSSになりますね PHPで呼び出した文字列内の特殊文字で、JavaScriptエラーが出る場合の対処法 | PLUS plus.vc/web/javascript… @plus_iさんから
— 徳丸 浩さん (@ockeghem) 2013年3月4日
たしかに、以下のコードは脆弱性がありました。
<? $data[0]="</script><script>alert(1)//"; $data[0]=preg_replace("/&/","&",$data[0]); $data[0]=preg_replace("/'/","'",$data[0]); $data[0]=preg_replace("/"/",""",$data[0]); $data[1]="');alert('XSS"; ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script> function test(){ } var a=["<? echo $data[0]; ?>"]; </script> </head> <body> <a href="javascript:test('<? echo htmlspecialchars($data[1]); ?>')">リンク</a> </body> </html>
これをブラウザ開くと、Scriptが実行されてしまいます。最初にhtmlspecialcharsを使うことを考えたのですが、上記のリンクをクリックすると分かるように、これもScriptが実行されてしまい、安全ではありませんでした。
<? // 文字列をすべて uXXXX 形式に変換 function unicode_escape($matches) { $u16 = mb_convert_encoding($matches[0],'UTF-16','UTF-8'); return preg_replace('/[0-9a-f]{4}/','u$0',bin2hex($u16)); } // 英数字とマイナス、ピリオド以外を uXXXX 形式でエスケープ function escape_js_string($s) { return preg_replace_callback('/[^-.0-9a-zA-Z]+/u','unicode_escape',$s); } $data[0]="</script><script>alert(1)//"; $data[1]="');alert('XSS"; ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script> function test(){ } var a=["<? echo escape_js_string($data[0]); ?>"]; </script> </head> <body> <a href="javascript:test('<? echo htmlspecialchars(escape_js_string($data[1])); ?>')">リンク</a> </body> </html>
そして、これが解決策です。徳丸さんが書かれている「体系的に学ぶ 安全なWebアプリケーションの作り方」113Pに記載されているUnicodeエスケープを使っています。これで不正なスクリプトは実行出来ません。unicode_escapeとescape_js_stringを使って、英数字以外を/uXXXXというUNICODE形式にエスケープしています。
さらに詳しくは以下、徳丸さんの本は詳しくて参考になります。
[sc name=”engeneer”]
SPONSER
SHARE
YouTube
PROFILE
