How to safely embed JSON object in HTML document

Hi all,

I'm working on a Backbone.js single page app with Rails 3.1, and in an
attempt to save on HTTP requests, I want to embed initial data set in
a HTML document that is sent back to the browser after successful
login.

I was thinking I can simply convert my ruby object to JSON, then HTML
escape resulting string of JSON, and then use that as a value for
JavaScript variable. Something like this:

<% tags = [{name:"tag1", color:"green"}, {name:"</script><b>I can do
something bad here</b>", color:"red"}] %>

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  var tags_list = <%= tags.to_json %>;
  // ]]>
</script>

However, this escapes all the double quotes in that string, which
triggers a "SyntaxError: Unexpected token &" in Chrome:

var tags_list =
[{&quot;name&quot;:&quot;tag1&quot;,&quot;color&quot;:&quot;green&quot;},
{&quot;name&quot;:&quot;&lt;/script&gt;&lt;b&gt;I can do something bad
here&lt;/b&gt;&quot;,&quot;color&quot;:&quot;red&quot;}];

If I remove the Rails' default HTML escaping with <%=raw tags.to_json
%>, then it returns this:
var tags_list = [{"name":"tag1","color":"green"},{"name":"</

<b>I can do something bad here</b>","color":"red"}];

which, of course, breaks the HTML document with "</script>".

I guess what I really want is to tell to_json() method to HTML escape
keys and values inside JSON object(s), instead of it returning the
JSON string unescaped, and then having Rails escape that whole string.
I guess what I need is something like this:

var tags_list = [{"name":"tag1","color":"green"},{"name":"&lt;/
script&gt;&lt;b&gt;I can do something bad here&lt;/
b&gt;","color":"red"}];

I thought about storing JSON string in a <script type="application/
json" id="json_string"> tag, and then doing something like

$.parseJSON($("#json_string").html())

but that also has the same problem of escaping, like in the above
example.

Is there any easy (Rails) way to do that? Or am I doing it wrong to
begin with?

Cheers!

Hi Alex,

What is it that you’re actually trying to do? I don’t think its such a good idea to put a JSON string on the client side as it can be manipulated to no end.

Why not just call the JSON object directly from the controller instead?

David
@davidchua

David,

I want to embed it in HTML so that I can just send that one HTML page to user after log in, and no other HTTP requests are needed before the user can start using the app.

This is because it would take several small, but slow, HTTP requests to gather all the data that is needed to show the page. I guess I could whip up a special API method that would return all the data in a single HTTP roundtrip, but if I can pull off this JSOPN embedding, then I can skip even that one extra HTTP requests for initial load. After initial load, app will rarely be needing data from the server, and when it does, it will be using regular API to get that data.

This is all just a performance optimization, since most of our users are on a high latency network (mobiles), so those HTTP requests really take a while, and this is an attempt to just skip them altogether.

Is there no easy way to embed HTML safe JSON in an HTML document, and have it parsed by JavaScript engine at the same time?

Thanks,

Alex

Alex Duck wrote in post #1018609:

Is there no easy way to embed HTML safe JSON in an HTML document, and
have
it parsed by JavaScript engine at the same time?

You could Base64 encode the JSON and decode it on the client-side with
JavaScript.

I am ABSOLUTELY NOT recommending that you do this, but simply stating
that it could work. Still a bad design idea IMHO.

I have no idea why embedded json would be considered worse than the
rest of the page that is sent down. I do it all the time, usually with
small items though, so I haven't have the problem you are describing.
I was hoping that someone would have a suggestion of a built in method
to call.

I've had to do this in a helper that was constructing a complicated
object, and I think this is similar to your problem:

1) enumerate through all the parts of your object that could contain
dangerous data and call h() on them.
2) call raw(your_object.to_json) on the result.

It's definitely not an easy, generic solution, but it gets you past
this problem.

The purpose of JSON is to be able to interchange the data between
various systems. As you are not going to do that then why use JSON at
all?

Honestly if you are going to process the JSON with Javascript what
dont you write your data out as Javascript data structures (which it
would be converted from JSON anyway) in the page and process that?
What do you gain from embedding the JSON then having to convert it
into Javascript data structures over just writing the native
Javascript data structures?

Paul,

thanks for the suggestion. I was hoping there is something in Rails to do that for me. But I guess there isn’t.

Other suggestion I got, off this list, is to have JSON embedded in a javascript string, and parsed by jQuery into an object. With proper javascript escaping (by j method), that gets the job done. And I like that approach better then calling h on attributes on server side, as this is more generic IMO, since it will work for any Ruby object.

Here is the code that works:

<% tags = [{name:“tag1”, color:“green”}, {name:“I can \n\ndo something bad here”, color:“red”}] %>

And that results in:

Thanks all!

I'm surprised that Rails doesn't have a built-in way of doing this!
As Paul said, I can't think of why embedded json would be worse than
any other way of transmitting the data, especially for things like
backbone apps.

As I mentioned on http://stackoverflow.com/questions/7205902/how-to-safely-embed-json-in-html-document/
a workaround is:

<script type="text/javascript" charset="utf-8">
  //<![CDATA[
  var tags_list = <%=raw @tags.to_json.gsub('/', '\/') %>;
  // ]]>
</script>

but that's kind of ugly. Again, I'm surprised there isn't a built-in
way of passing JSON data to from controller to view like this. Am I
missing some obvious reason why?