0
  1. I am trying to show attributes of a resource with javascript. I'm sure I'm making a simple mistake or omission.

  2. I am trying to understand how j render works and why it is necessary. I know it has something to do with the scenario where a malicious user inputs javascript and it would be executed in the application which could cause bad things to happen.

Setup: Simple blog template in a rails app: rails g scaffold Blog title:string content:text

views/blogs/show.html.erb

<div id="blogContent"> Javascript should enter result of @blogger.content here: </div>

assets/javascripts/blogs.coffee

$document.on "page:change", ->
    $blogPost = "<%= j render(@blog.content) %>"
    alert($blogPost)
    $('#blogContent').append($blogPost)

Here are the issues I'm running into:

  1. The alert box is literally returning: <%= j render(@blog.content %>. I want it to return that blog's content.

  2. Once I get it functioning to where the blog's content is showing, I want to prove to myself that it is necessary to escape javascript so that malicious user input is not executed in my application. So for example, if inside the content a malicious user inputted: <a href='DangerousSite.xyz'>Hacker says click for free stuff</a> Then what would result from my app rendering @blog.content would be a link that says: Hacker says click for free stuff. Once I prove to myself that escaping javascript is necessary to prevent stuff like this, I want to be able to escape it and have the result literally show <a href="Dangerous Site">Hacker says click for free stuff</a>, or whatever else way the rendered sanitized javascript looks like.

Neil
  • 4,578
  • 14
  • 70
  • 155

2 Answers2

1

To answer your first portion about escaping Javascript let's take a look at this code:

$blogPost = "<%= j render(@blog.content) %>"

Now imagine a user decided to begin their blog post with a quote from DHH:

“Workaholics don't actually accomplish more than nonworkaholics.” 

Now since Javascript in this context happens on the client-side, the Ruby in your code gets evaluated first. Thus your Javascript now looks like this:

$blogPost = "“Workaholics don't actually accomplish more than nonworkaholics.”"

As you can see, there is an extra set of quotes in there which breaks out of the string. The actual quote is going to be read as Javascript by the interpreter, which will break because that is invalid Javascript. A malicious user could take advantage of this by rewriting their blog post to contain Javascript instead of a quote. To fix this we escape the quotes with j (short for escape_javascript), so:

“Workaholics don't actually accomplish more than nonworkaholics.”

Becomes:

\&quot;Workaholics don't actually accomplish more than nonworkaholics.\&quot;

Now onto your second portion. The reason your code is literally returning "j render(@blog.content)" is because that part of your code is Ruby and needs to be handled by ERB before your Javascript gets sent to the browser. To have ERB handle this file, simply add .erb to your file name:

assets/javascripts/blogs.coffee.erb

However, this is a bad practice because the Javascript in your assets is in a different context than your app so I suspect it will not find the @blogs variable. Thus you should move your blogs.coffee.erb file to the appropriate view folder, something like this:

app/views/blogs/index.coffee.erb

(Though once you move it into the views, I believe the .erb is no longer needed, as Rails implies it)

trosborn
  • 1,658
  • 16
  • 21
0


1. You'll probably want to follow some tips at the following:
Rails: access controller instance variable in CoffeeScript or JavaScript asset file

2. If you're avoiding HTML, you should escape HTML, from what I've read, j render will only escape Javascript, and prevent that from running, but not prevent HTML, like the example you gave.

To escape HTML with JavaScript, use a handy function like this:

var entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": '&#39;',
"/": '&#x2F;'
};

function escapeHtml(string) {
    return String(string).replace(/[&<>"'\/]/g, function (s) {
      return entityMap[s];
    });
}

Taken from Handlebars: https://github.com/wycats/handlebars.js/blob/0a9fc171b00a12fa990d2f7d27310182ed51a41c/lib/handlebars/utils.js

Community
  • 1
  • 1
Josh
  • 100
  • 6
  • escape_javascript does not escape HTML because Rails escapes HTML by default, and only displays HTML if you override that default with the html_safe method – trosborn Feb 09 '15 at 22:37