Best practice for embedding arbitrary JSON in the DOM?

JavascriptJsonDomEmbeddingDecoupling

Javascript Problem Overview


I'm thinking about embedding arbitrary JSON in the DOM like this:

<script type="application/json" id="stuff">
    {
        "unicorns": "awesome",
        "abc": [1, 2, 3]
    }
</script>

This is similar to the way one might store an arbitrary HTML template in the DOM for later use with a JavaScript template engine. In this case, we could later retrieve the JSON and parse it with:

var stuff = JSON.parse(document.getElementById('stuff').innerHTML);

This works, but is it the best way? Does this violate any best practice or standard?

Note: I'm not looking for alternatives to storing JSON in the DOM, I've already decided that's the best solution for the particular problem I'm having. I'm just looking for the best way to do it.

Javascript Solutions


Solution 1 - Javascript

I think your original method is the best. The HTML5 spec even addresses this use:

> "When used to include data blocks (as opposed to scripts), the data > must be embedded inline, the format of the data must be given using > the type attribute, the src attribute must not be specified, and the > contents of the script element must conform to the requirements > defined for the format used."

Read here: http://dev.w3.org/html5/spec/Overview.html#the-script-element

You've done exactly that. What is not to love? No character encoding as needed with attribute data. You can format it if you want. It's expressive and the intended use is clear. It doesn't feel like a hack (e.g. as using CSS to hide your "carrier" element does). It's perfectly valid.

Solution 2 - Javascript

As a general direction, I would try using HTML5 data attributes instead. There's nothing to stop you putting in valid JSON. e.g.:

<div id="mydiv" data-unicorns='{"unicorns":"awesome", "abc":[1,2,3]}' class="hidden"></div>

If you're using jQuery, then retrieving it is as easy as:

var stuff = JSON.parse($('#mydiv').attr('data-unicorns'));

Solution 3 - Javascript

This method of embedding json in a script tag has a potential security issue. Assuming the json data originated from user input, it is possible to craft a data member that will in effect break out of the script tag and allow direct injection into the dom. See here:

http://jsfiddle.net/YmhZv/1/

Here is the injection

<script type="application/json" id="stuff">
{
    "unicorns": "awesome",
    "abc": [1, 2, 3],
    "badentry": "blah </script><div id='baddiv'>I should not exist.</div><script type="application/json" id='stuff'> ",
}
</script>

There is just no way around escaping/encoding.

Solution 4 - Javascript

See Rule #3.1 in OWASP's XSS prevention cheat sheet.

Say you want to include this JSON in HTML:

{
    "html": "<script>alert(\"XSS!\");</script>"
}

Create a hidden <div> in HTML. Next, escape your JSON by encoding unsafe entities (e.g., &, <, >, ", ', and, /) and put it inside the element.

<div id="init_data" style="display:none">
		{&#34;html&#34;:&#34;&lt;script&gt;alert(\&#34;XSS!\&#34;);&lt;/script&gt;&#34;}
</div>

Now you can access it by reading the textContent of the element using JavaScript and parsing it:

var text = document.querySelector('#init_data').textContent;
var json = JSON.parse(text);
console.log(json); // {html: "<script>alert("XSS!");</script>"}

Solution 5 - Javascript

I'd suggest to put JSON into an inline script with a function callback (kind of JSONP):

<script>
someCallback({
    "unicorns": "awesome",
    "abc": [1, 2, 3]
});
</script>

If the executing script is loaded after the document you can store this somewhere, possibly with an additional identifier argument: someCallback("stuff", { ... });

Solution 6 - Javascript

HTML5 includes a <data> element for keeping machine readable data. As a—perhaps safer—alternative to <script type="application/json"> you could include your JSON data inside the value attribute of that element.

const jsonData = document.querySelector('.json-data');
const data = JSON.parse(jsonData.value);

console.log(data)

<data class="json-data" value='
  {
    "unicorns": "awesome",
    "abc": [1, 2, 3],
    "careful": "to escape &#39; quotes"
  }
'></data>

In this case you need to replace all single quotes with &#39; or with &quot; if you opt to enclose the value with double quotes. Otherwise your risk XSS attacks like other answers have suggested.

Solution 7 - Javascript

My recommendation would be to keep JSON data in external .json files, and then retrieve those files via Ajax. You don't put CSS and JavaScript code onto the web-page (inline), so why would you do it with JSON?

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
QuestionBen LeeView Question on Stackoverflow
Solution 1 - JavascriptJamie TreworgyView Answer on Stackoverflow
Solution 2 - JavascriptHoratio AlderaanView Answer on Stackoverflow
Solution 3 - JavascriptMadCoderView Answer on Stackoverflow
Solution 4 - JavascriptMatthewView Answer on Stackoverflow
Solution 5 - JavascriptcopyView Answer on Stackoverflow
Solution 6 - JavascriptRúnar BergView Answer on Stackoverflow
Solution 7 - JavascriptŠime VidasView Answer on Stackoverflow