なぜパーシャルをレンダリングする前にescape_javascriptですか?


120

私はこのRailscastエピソードを見ていて、なぜescape_javascriptここに呼び出しが必要なのか疑問に思っています。

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");

何にescape_javascript使用されますか?

Railsのドキュメントによると:

escape_javascript(javascript)

JavaScriptセグメントのエスケープキャリアリターンと一重引用符および二重引用符。

しかし、それは私にはあまり意味がありません。


23
ちなみに、ここで受け入れられた答えは正しい答えではありません。Kikito's is
Steve

回答:


-3

ブラウザが実際に実行するJavaScriptをユーザーが投稿したくないので、


4
しかし、JavaScriptコードを渡してレンダリングする場合はどうでしょうか?
berto77

ええ、実際には、それはフォーマット方法の詳細です。ユーザーが自分のJavaScriptを実行することを妨げるものではありません。それを防ぐことはできません。
LasagnaAndroid 2015

3
これは役に立ちません。代わりにキキトの答えを見てください。
nitsas 16

363

コードを2つの部分に分割すると、理解しやすくなります。

最初の部分$("#reviews").append("<%= ... %>");は、erbを使用したJavaScriptです。これは、<%= ... %>がその中のルビコードが返すものに置き換えられることを意味します。その置換の結果は有効なJavaScriptである必要があります。そうでない場合、クライアントが処理しようとするとエラーがスローされます。それが最初のことです。有効なJavaScriptが必要です。。

もう1つ考慮すべきことは、rubyが生成するものはすべて、二重引用符で囲まれたjavascript文字列内に含まれている必要があること<%= ... %>です。つまり、生成されるJavaScriptは次のようになります。

$("#reviews").append("...");

次に、内のルビ部分を調べてみましょう<%= ... %>。なにrender(:partial => @review)ますか?それは部分的なレンダリングです-つまり、それはあらゆる種類のコード-html、css ...またはさらに多くのJavaScriptをレンダリングする可能性があることを意味します!

では、パーシャルにこのような単純なhtmlが含まれているとどうなりますか?

<a href="/mycontroller/myaction">Action!</a> 

あなたのjavascriptが二重引用符で囲まれた文字列をパラメータとして取ったことを覚えていますか?を単に<%= ... %>その部分コードに置き換えると、問題が発生します- href=二重引用符がある直後!JavaScriptは無効になります:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");

これが起こらないようにするには、これらの特殊文字をエスケープして文字列がカットされないようにする必要があります。代わりにこれを生成するものが必要です。

<a href=\"/mycontroller/myaction\">Action!</a>

これは何をescape_javascriptします。返される文字列がJavaScriptを「破壊」しないようにします。これを使用すると、必要な出力が得られます。

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")

よろしく!


4
本当に、とても素敵な説明ありがとうございます。実際のJavaScriptをエスケープするために実際には使用していないので、「escape_javascript」を使用するのは誤解を招くようなものだと思います。スクリプトタグをパーシャルに挿入して、必要なJavaScriptを実行できます。
Steve

13
@Steveも同意しました。escape_for_javascript他のコード(htmlなど)をエスケープして、javascriptを壊さないようにすることがよくあるためです。
キキト2013年

14
escape_javascript()今ではより短いメソッドがあります:simpley j()(少なくともRails 4では)。
mjnissim 2013

@kikito、この効果を使用して、リモートフォームで構成されるhtmlパーシャルをレンダリングしようとしていますか?JavaScript経由で送信する別のフォームを含むJavaScriptでパーシャルをレンダリングすると、2番目のリクエストがjsではなくhtmlになる理由を見つけようとしています。時間があれば、これに関して私がすでに投稿した質問を見てください。ありがとう!私の質問
ジェイクスミス

1
@JakeSmithがあなたの質問に回答しました
kikito

8

ユーザーは悪意のあるコード(悪意のあるユーザー)を投稿する可能性があり、エスケープしないままにしておくと実行される可能性があり、ユーザーがアプリケーションを制御できるようになります。

これを試して:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");

レールの構文にはあまり慣れていませんが、エスケープしないと variable警告ボックスが表示され、これは意図的な動作ではないと思います。


8

ここで出典を見るとではるかに明確になります。

この関数は、次の2つのことを実行します。

  1. 入力文字列の文字をJS_ESCAPE_MAPで定義された文字に置き換えます

    これの目的は、JavaScriptコードが埋め込まれている外側の文字列に干渉することなく、JavaScriptコードが正しくシリアル化されるようにすることです。たとえば、javascript文字列が二重引用符で囲まれている場合、文字列リテラル内のすべての引用符は、コードが壊れないように単一引用符で囲む必要があります。

  2. 関数は、結果の文字列がHTMLセーフかどうかもチェックします。そうでない場合は、必要なエスケープを行って、文字列がHTMLセーフになり、結果が返されることを確認します。

escape_javascriptを使用している場合、通常は別の文字列または既存のHTML内に動的に埋め込まれています。これを行うと、ページ全体がレンダリングされないことを確認する必要があります。

この応答のいくつかの側面が他の応答で指摘されましたが、JavaScriptエスケープとhtmlエスケープの違いを含むすべての項目をまとめたいと思いました。また、一部の応答は、この関数がスクリプトインジェクションを回避するのに役立つことをほのめかしています。それがこの機能の目的ではないと思います。たとえば、レビューにアラート(「こんにちは」)がある場合、レビューをノードに追加するだけではポップアップは起動しません。ページの読み込みやその他のイベントによってトリガーされる関数内に埋め込みません。htmlの一部としてアラート(「こんにちは」)があるだけでは、JavaScriptとして実行されるわけではありません。

それでも、スクリプトインジェクションが不可能であることを否定していません。ただし、これを回避するには、ユーザーデータを取得してデータベースに格納するときに手順を実行する必要があります。提供する機能と例は、すでに保存されている情報のレンダリングに関連しています。

これがあなたの質問に役立ち、答えることを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.