JavaScript文字列のエスケープを回避する方法

(Last Updated On: 2018年8月13日)

JavaScriptの文字列をエスケープのエントリでJavaScript文字列をエスケープ後に直接出力するより、DOMから取得してはどうか?という提案があったのでエントリを作成しました。

まずJavaScript文字列をJavaScript文字列のエスケープで作成したescape_javascript_string関数を利用した場合の例です。

<span onmouseover="alert('<?php echo escape_javascript_string('Hello From <php>')?>');">マウスをのせてね!</span>

JavaScriptでDOMの要素から取得する場合、以下のようになります。要素の取得にはjQueryを利用しています。

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<span onmouseover="alert($('#msg').text());">マウスをのせてね!</span>
<div style="display: none" id="msg"><?php echo htmlentities('Hello From <dom>', ENT_QUOTES, 'UTF-8') ?></div>

こういう使い方がどうか?という議論は置いておくとして、DOMのノードへ出力し、データ保存先として利用する方法でも同じ事を実現できます。メリットは次のようになります。

  • JavaScript用文字列にエスケープせずに、HTML用にエスケープできる

デメリットは次のようになります。

  • JavaScript文字列を設定する事は禁止できない
  • IDの管理が必要になり、HTMLが複雑になる
  • headの中で行った場合、おかしなHTMLになるか、離れた場所に文字列を置くことになる

HTMLエスケープにエスケープ方法を統一できるメリットはありますが、デメリットの方が多いです。セキュリティ的には「サーバ側で禁止できない」ことが問題です。プログラマが「ここに書き出したい」と思っているのに「適切な書き出し方」を解説しないのはセキュリティ書籍としては問題でしょう。システム開発的にはHTMLが複雑になることはコスト増につながります。

似たような方法にはメッセージを別のJavaScriptファイルに置く方法があります。クライアント側でi18n化を行う場合に良く用いられる方法です。この場合、MIMEタイプにtext/javascriptを指定すればJavaScriptの\エスケープでも安全です。ただし、ブラウザがMIMEタイプ無視して推測したり、バグがある場合はこの限りではありません。escape_javascrpt_string()でエスケープしても正しくデコードされるので、エスケープ処理してしまった方が良いと思います。コピー&ペーストでHTMLの中に埋め込まれてしまった場合にも安全です。

DOMからJavaScriptで利用するテキストを取得する方法は「出力先をHTMLに変更」しているだけです。ブラウザに対する全ての出力に同じ手法が使えるのであれば利用を検討する価値もあると思いますが、それも出来ません。

HTMLのコンテンツとして出力する場合に安全に出力する方法やDOMの安全な利用方法は別の項目でカバーします。このJavaScript文字列エスケープを回避する手法を解説する必要性はあまり無いと考えています。いかがでしょうか?一応、載せておくべきでしょうか?

PHPのセキュリティ入門書に記載するコンテンツのレビューも兼ねてPHP Securityカテゴリでブログを書いています。コメント、感想は大歓迎です。

投稿者: yohgaki