Why escape_javascript before rendering a partial?

JavascriptRuby on-Rails

Javascript Problem Overview


I'm looking at this Railscast episode and wondering why the call to escape_javascript is needed here:

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

What is escape_javascript used for?

According to the Rails docs:

> escape_javascript(javascript) > > Escape carrier returns and single and > double quotes for JavaScript segments.

But that doesn't mean much to me.

Javascript Solutions


Solution 1 - Javascript

It's easier to understand if you split the code in two parts.

The first part $("#reviews").append("<%= ... %>"); is javascript with erb. This means that the <%= ... %> will be replaced by whatever the ruby code inside of it returns. The result of that replacement must be valid javascript, otherwise it will throw an error when the client tries to process it. So that's the first thing: you need valid javascript.

Another thing to take into account is that whatever ruby generates must be contained inside a javascript string with double quotes - notice the double quotes around the <%= ... %>. This means that the generated javascript will look like this:

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

Now let's examine the ruby part inside the <%= ... %>. What does render(:partial => @review) do? It is rendering a partial - which means that it could be rendering any kind of code - html, css ... or even more javascript!

So, what happens if our partial contains some simple html, like this one?

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

Remember that your javascript was taking a double-quoted string as a parameter? If we simply replace the <%= ... %> with the code of that partial, then we have a problem - immediately after the href= there is a double quote! The javascript will not be valid:

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

In order for this not to happen, you want to escape these special characters so your string is not cut - you need something that generates this instead:

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

This what escape_javascript does. It makes sure that the string returned will not "break" javascript. If you use it, you will get the desired output:

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

Regards!

Solution 2 - Javascript

users may post malicious code (malicious users) that if left unescaped will potentially get executed, allowing users to control your application.

try this:

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

not really familiar with the syntax of rails, but if you don't escape variable then an alert box will show, and i dont think that is intended behaviour.

Solution 3 - Javascript

If you look at the source here, it will be much clearer.

This function accomplishes the following two things:

  1. It substitutes the characters in the input string with the ones defined in JS_ESCAPE_MAP

    The purpose of this is to make sure that the javascript code is serialized correctly without interfering with the outer string within which it is being embedded. For example if you have a javascript string in double quotes then all the quotes within for string literals must be in single quotes to avoid the code from breaking.

  2. The function also checks if the resulting string is html safe. If it is not then it does the necessary escaping to make sure that the string becomes html safe and returns the result.

When you are using escape_javascript, it is usually being embedded within another string or existing html dynamically. You need to make sure that doing this will not make your entire page not render.

Some aspects of this response were pointed out in other responses but I wanted to bring all the items together include the difference between javascript escaping and html escaping. Also, some responses allude that this function helps to avoid script injection. I don't think that is the purpose of this function. For example, in your review if your review has alert('hi there'), just appending it to the node will not fire the pop-up. You are not embedding it within a function that is triggered on page load or through some other event. Merely having alert('hi there') as part of your html does not mean that it will execute as javascript.

That said I am not denying that script injection is not possible. But to avoid that you need to take steps when you take the user data and store it in your database. The function and example you are providing are related to rendering the information, which was already saved.

I hope this helps and answers your question.

Solution 4 - Javascript

Because you don't want users posting JavaScript that the browser actually executes?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLee TangView Question on Stackoverflow
Solution 1 - JavascriptkikitoView Answer on Stackoverflow
Solution 2 - JavascriptbarkmadleyView Answer on Stackoverflow
Solution 3 - JavascriptTabrezView Answer on Stackoverflow
Solution 4 - JavascriptAzeem.ButtView Answer on Stackoverflow