web-dev-qa-db-ja.com

<script>ブロック内のJavaScript文字列リテラルでHTMLエンティティをエスケープする

一方で私が持っている場合

<script>
var s = 'Hello </script>';
console.log(s);
</script>

ブラウザは<script>ブロックを早期に終了し、基本的にページがめちゃくちゃになってしまいます。

一方、文字列の値はユーザーから取得される場合があります(たとえば、以前に送信されたフォームを介して、文字列が<script>ブロックにリテラルとして挿入されるようになる)ため、何でも期待できます悪意を持って形成されたタグを含む、その文字列内。ここで、ページの生成時にhtmlentities()で文字列リテラルをエスケープすると、エスケープされたエンティティがsの値にリテラルに含まれます。つまり、sは出力されます

Hello &lt;/script&gt;

この場合、これは望ましい動作ではありません。

<script>ブロック内のJS文字列を適切にエスケープする1つの方法は、左山括弧の後にスラッシュをエスケープするか、または常にスラッシュをエスケープすることです。

var s = 'Hello <\/script>';

これは正常に動作しているようです。

次に、HTMLイベントハンドラー内のJSコードの問題が発生します。

<div onClick="alert('Hello ">')"></div>

最初は有効に見えますが、ほとんど(またはすべて?)のブラウザーでは機能しません。これには、明らかに完全なHTMLエンティティエンコーディングが必要です。

私の質問は:上記のすべての状況を適切にカバーするためのベスト/標準的なプラクティスは何ですか?つまり、スクリプトブロック内のJS、イベントハンドラー内のJS-JSコードがサーバー側で部分的に生成され、悪意のあるデータを含む可能性がある場合?

26
mojuba

次の文字couldはHTMLまたはJavascriptパーサーに干渉し、文字列リテラルでエスケープする必要があります:<, >, ", ', \,および&

エスケープ文字を使用したスクリプトブロックでは、ご存知のように機能します。連結メソッド(</scr' + 'ipt>')読みにくい場合があります。

var s = 'Hello <\/script>';

HTMLのインラインJavaScriptでは、エンティティを使用できます。

<div onClick="alert('Hello &quot;>')">click me</div>

デモ: http://jsfiddle.net/ThinkingStiff/67RZH/

両方で機能するメソッド<script>ブロックとインラインJavascriptは\uxxxx、ここでxxxxは16進文字コードです。

  • <-\u003c
  • >-\u003e
  • "-\u0022
  • '-\u0027
  • \-\u005c
  • &-\u0026

デモ: http://jsfiddle.net/ThinkingStiff/Vz8n7/

HTML:

<div onClick="alert('Hello \u0022>')">click me</div>

<script>
    var s = 'Hello \u003c/script\u003e';
alert( s );
</script>   
40
ThinkingStiff

(編集-どういうわけかあなたの質問でスラッシュエスケープがすでに言及されていることに気づかなかった...)

わかりましたので、スラッシュをエスケープする方法を知っています。

インラインイベントハンドラーでは、リテラル内で境界文字を使用できないため、もう1つを使用します。

<div onClick='alert("Hello \"")'>test</div>

しかし、これはすべてあなたの人生を困難にする助けになります。インラインイベントハンドラーは使用しないでください。または、どうしても必要な場合は、他の場所で定義された関数を呼び出させる必要があります。

一般的に言って、サーバー側のコードがJavaScriptを記述している理由はほとんどありません。サーバーからスクリプトを生成しないでください。代わりに、事前に記述されたスクリプトにデータを渡してください。

(元の)

バックスラッシュを使用して、JS文字列リテラルのすべてをエスケープできます(それ以外の場合は、特別なエスケープ文字ではありません)。

var s = 'Hello <\/script>';

これには、htmlとして解釈されないようにするというプラスの効果もあります。したがって、「/」を「\ /」で全面的に置き換えると、悪影響はありません。

ただし、一般的には、ユーザーが送信したデータがJavaScriptの文字列リテラルとして埋め込まれるのではないかと心配しています。サーバーでJavaScriptコードを生成していますか? JSONやHTMLの「データ」属性などとしてデータを渡さないのはなぜですか?

2
Jamie Treworgy

これが私のやり方です:

function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}

var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';

test.value=encode(myString);

testing.innerHTML=encode(myString);

/*************
* \x26 is &ampersand (it has to be first),
* \x0A is newline,
*************/
<textarea id=test rows="9" cols="55"></textarea>

<div id="testing">www.WHAK.com</div>
2
Dave Brown

ベストプラクティスはそもそもインラインJSを避ける​​だと思います。

JSコードを別のファイルに入れ、src属性を付けてインクルードします

<script src="path/to/file.js"></script>

それを使用して、HTMLにイベントハンドラーを配置する代わりに、内部からイベントハンドラーを設定します。

//jquery example
$('div.something').on('click', function(){
    alert('Hello>');
})
2
hugomg