web-dev-qa-db-ja.com

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

このRailscastエピソード を見て、なぜescape_javascriptはここで必要です:

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

とは escape_javascript のために使用される?

the Rails docs

escape_javascript(javascript)

JavaScriptセグメントのキャリアリターンと一重引用符と二重引用符をエスケープします。

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

119
Lee Tang

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

最初の部分$("#reviews").append("<%= ... %>");は、erbを含むjavascriptです。つまり、<%= ... %>は、その中のRubyコードが返すものは何でも置き換えられます。置き換えの結果は有効なjavascriptでなければなりません。そうでない場合、クライアントがエラーをスローしますそれを処理しようとするので、それが最初のことです:有効なjavascriptが必要です。

考慮すべきもう1つのことは、Ruby生成するものはすべて、二重引用符付きのjavascript文字列内に含まれている必要があることです。<%= ... %>このように見える:

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

では、<%= ... %>内のRuby部分を調べてみましょう。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>");

これが起こらないようにするには、escapeこれらの特殊文字を使用して、文字列が切り取られないようにします-代わりにこれを生成するものが必要です:

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

これはescape_javascriptが行うことです。返される文字列がjavascriptを「壊さない」ようにします。使用すると、目的の出力が得られます。

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

よろしく!

357
kikito

ソース here を見ると、より明確になります。

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

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

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

  2. 関数は、結果の文字列がhtmlセーフかどうかもチェックします。そうでない場合は、文字列がhtmlセーフになるように必要なエスケープを行い、結果を返します。

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

この応答のいくつかの側面は他の応答で指摘されましたが、javascriptエスケープとhtmlエスケープの違いを含むすべてのアイテムをまとめたいと思いました。また、一部の回答では、この関数がスクリプトインジェクションの回避に役立つことを示唆しています。それがこの機能の目的ではないと思います。たとえば、レビューにアラート(「こんにちは」)がある場合、レビューをノードに追加してもポップアップは表示されません。ページのロード時または他のイベントを介してトリガーされる関数内に埋め込みます。 HTMLの一部として単にalert( 'hi there')を持っているからといって、それがjavascriptとして実行されるわけではありません。

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

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

8
Tabrez

ユーザーは悪意のあるコード(悪意のあるユーザー)を投稿する可能性があります。

これを試して:

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

railsの構文にあまり詳しくありませんが、variableをエスケープしないと、アラートボックスが表示されますが、これは意図した動作ではないと思います。

8
barkmadley