Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for embedding arbitrary JSON in the DOM?

People also ask

How do I beautify JSON in HTML?

use a <pre> tag to JavaScript pretty prints JSON in HTML. The <pre> need id to show data on it. Where pre tells the browser engine that the content inside is pre-formatted and can be displayed without any modification. To convert it to JSON and pretty print use stringify method.

What should an object in JSON be enclosed with?

JSON has the following syntax. Objects are enclosed in braces ( {} ), their name-value pairs are separated by a comma ( , ), and the name and value in a pair are separated by a colon ( : ). Names in an object are strings, whereas values may be of any of the seven value types, including another object or an array.

What is JSON Dom?

Document Object Model(DOM) is an in-memory representation of JSON for query and manipulation. The basic usage of DOM is described in Tutorial.

Does JSON preserve ordering?

Yes, the order of elements in JSON arrays is preserved. From RFC 7159 -The JavaScript Object Notation (JSON) Data Interchange Format (emphasis mine): An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.


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.


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'));

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.


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>"}

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", { ... });


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.