I'm looking for most elegant way of "dumping" simple JavaScript object into JavaScript source-code generated on-fly.
Purpose:
Assume we have node.js server generating HTML. We have an object x on server side. The object is simple - only strings/ints/arrays in it (so, it's JSON-able). I want to "embed" object x into HTML being generated, to be available for JavaScript code which will run on the browser. So the code:
console.log(x);
will dump exactly the same data on both server-side and browser-side.
For example - imagine I'm going to pass some additional config/data to JavaScript running on browser.
Obvious solutions:
Encoding as JSON and send as AJAX/Websocket is not a part of this question as we have to embed the object in the HTML. I don't want additional HTTP requests - everything should be passed in one go.
Encoding as JSON and simply attach to variable sounds initially good, but involves some additional escaping steps.
Using util.inspect() works for me, in this way:
var toHtml = 'var x = ' + util.inspect(theXonServer, {depth:9}) + ';';
but I'm not sure if it's "elegant" (and secure and error-prone and...)
Any better suggestions ? Standard way of doing that ?
The Wrong Way to Pass Data
It's common to get advice to just stringify some JSON and dump it into a <script> tag. This is bad advice. Don't do it.
It's important to understand why this is a bad idea.
When you string-build JavaScript, you're opening yourself up to all sorts of quirks of the language that you'd absolutely be required to understand to make sure that there are no issues.
One such quirk is that within a <script> element, the first occurrence of </script> will close the <script> element. It doesn't matter that it's in a string, the script will be closed, and the rest of the contents after that point will be treated as HTML.
HTML escaping doesn't work because JS doesn't like HTML entities.
what might start as:
<script>
window.xss = <%= JSON HERE %>
</script>
could turn into:
<script>
window.xss = {"username":"Robert Hackerman</script><script src='nefarious.js'></script>"}
</script>
Don't risk it.
The Right Way to Pass Data...
...When the Page is Rendering
The much safer way that prevents any script execution is via [data-*] attributes. You must HTML-escape the contents, but that's OK in attributes. I'm using a <script> element because it's implied that the script will be using the data.
What would start as:
<script data-foo="<%= HTML ENCODED JSON HERE %>" src="yourscript.js"></script>
Would turn into:
<script data-foo="{"username":"Robert Hackerman</script><script src='nefarious.js'></script>"}" src="yourscript.js"></script>
And if you want access to that data, you can just access the attribute value, or use the dataset api (if your target browsers support it):
var fooElement = document.querySelector('[data-foo]');
var rawData = fooElement.dataset.foo;
// or
var rawData = fooElement.getAttribute('data-foo');
var data = JSON.parse(rawData);
console.log(data);
...After the Page has Rendered
If the page has already loaded, and you want to access some data, just use an AJAX request. You'll be able to safely read in a JSON data source, which can be piped through JSON.parse to access the data object.
Util.inspect vs JSON.stringify
You only need util.inspect if your object is circular. If it's JSON encodable in 99.9% of cases you can just output it to the source with JSON.stringify.
Using JSON
There are edge cases to this - not only are JS objects more expressive than JSON (functions etc), JSON objects can do things JS objects can't (in edge cases of encoding). So make sure not only is your object serializable correctly, it's also deserializable correctly. I also assume you didn't do anything crazy like override the array constructor (which would make JS objects behave differently from JSON ones).
Security
As for security, unless your object can contain sensitive data (and it really shouldn't, whitelist it first) there should not be any related issues.
Overall option 2 is a standard approach that is quite commonly used - including on this very site.
It usually works for simple data which is most data you need to share (numbers and strings).
It saves the round trip.
It's used very often in big sites and in practice.
Related
I've read a lot about sanitizing and escaping of untrusted data, e.g. starting with this cheat sheet. But I didnt get the full picture yet. I am struggeling to understand, what principles I have to follow in order to parse JSON data safely.
Let's be more precise by means of an example. I retreive an Object in JSON format via an Ajax call from my server. The object shoudnt contain any malicious code, but.... you never now. So I parse the JSON data using JSON.parse in JS. The sesult is a multilevel JS object. I use the object in various way, e.g. creating table code via JS and writing it in the DOM.
Is this approach safe. Or do I have to somehow escape the invidual items of the object individually? Appreciate your help. Happy to concrete my example if necessary.
According to this Angular 2 guide:
Don't expect the decoded JSON to be the heroes array directly. This server always wraps JSON results in an object with a data property. You have to unwrap it to get the heroes. This is conventional web API behavior, driven by security concerns.
('Heroes' is an array of objects).
The link in the above paragraph says :
Always return JSON with an Object on the outside
Always have the outside primitive be an object for JSON strings:
Exploitable:
[{"object": "inside an array"}]
Not exploitable:
{"object": "not inside an array"}
Also not exploitable:
{"result": [{"object": "inside an array"}]}
My Question is: Why shouldn't the server return something like a JSON array?
Say :
[
"apples"
,"oranges"
, "peaches"
]
How is this a security concern ?
To avoid JSON Hijacking:
The fact that this is a JSON array is important. It turns out that a script that contains a JSON array is a valid JavaScript script and can thus be executed. A script that just contains a JSON object is not a valid JavaScript file.
For example, if you had a JavaScript file that contained the following JSON: {“Id”:1, “Balance”:3.14} And you had a script tag that referenced that file:
<script src="http://example.com/SomeJson"></script>
You would get a JavaScript error in your HTML page. However, through an unfortunate coincidence, if you have a script tag that references a file only containing a JSON array, that would be considered valid JavaScript and the array gets executed.
So allowing JSON to be returned as anything but an object would make it possible to return a JSON array that contained code that could be run on the client level (in a context where the client isn't expecting it to be runnable, could be malicious, etc). Only returning JSON objects prevents this from happening.
This was rather bad advice that has since been removed from the angular tutorial.
The linked OWASP Cheet Sheet lists three ways to defend against JSON Hijacking. The one the tutorial picked is the hardest to implement correctly, because one must educate every single developer, and audit every single REST resource, rather than writing a single HttpInterceptor to extend CSRF-defenses to GET requests.
JSON hijacking can only occur due to browser bugs, which tend to be fixed quickly (this does not imply such attacks are impossible, but the easy exploits no longer work in modern browsers)
I want to create a website where the user enters data in a formular and a php-script uses this data to create html-code which shall be inserted in a div-element. Using AJAX seems to be the right way to do this, but there is one thing that bothers me. in my opinion a script should always generate a whole document (doctypt-declaration, head, body etc.), but if i use AJAX i have to send only a fragment of a whole document, because i would have to write something like this:
document.getElementById("mydiv").innerHTML = ajaxObject.responseText;
So i would like my PHP-script to send a whole document, but i cannot assign a whole document to the inner html of an element. is there a way that javascript can process a whole document, and insert the documents body in a div or should i maybe use iframes instead?
in my opinion a script should always generate a whole document
A big no to that! Have a look on other data formats such as json which is widely spread, or xml. Some formats do not even follow certain document structures that say: here my document starts, title belongs here, that must be like that, the other thing has to be like this and here the document ends. There's just bare data (of course under the accordance of the syntax).
The server doesn't need to return HTML at all (if you don't want it to). The opposite is the case. Provide as many output formats as you can.
Think of other client applications that would use your script, such as non-js applications or applications outside the browser that can't even handle HTML.
Would you always write a new script or change your existing whenever you need another output data format, or would you rather have a strong serverside application structure that can handle the output of several data formats?
Think of your server as an interface. It returns the data that you request. How you handle the data is absolutely up to the client (the server should not even care) in this case.
Also returning HTML chunks is absolutely okay in your case. That's what I would do here too.
What I want to point out is that you absolutely don't need your script to return a whole HTML document (isn't exactely that even a big advantage that came up with AJAX?)
If you don't mind using a bit of jQuery,
$('html').html(ajaxObject.responseText);
If you just want change whatever's in the body,
$('body').html(ajaxObject.responseText);
As suggested in the comment below, it without using jQuery,
document.body.innerHTML = ajaxObject.responseText;
New to JSON, just trying to get my feet wet.
I know how to do this with XML via javascript, but am trying to learn how to handle JSON objects so I can switch over.
Basically I want to search through all "permalink" tags in the following JSON object and, when I find the right one, save its corresponding "title" and "id" tags to javascript variables:
http://api.soundcloud.com/users/goldenstatewarriors/tracks.json?client_id=02db8e29aa2fb5bf590f478b73137c67
Can this be done with only javascript (no PHP)? The main issue I'm facing is simply grabbing the text from the page and converting it to a json object.
You need to use a JSON parser in order to transform the JSON string into an object you can handle natively in JavaScript. Recent browsers have this functionality built in as JSON.parse(), but obviously this will not work in older browsers (we're talking very old browsers here).
A solution to that problem is to use the JSON parsing library available here. If native browser support is detected, it simply uses that, otherwise it has a JavaScript implementation to achieve the same result. The file you'll need is json2.js - simply include that as you would any other library and away you go!
An example of the code would be:
var dataObject = JSON.parse(jsonData);
As a side note, XMLHttpRequest is somewhat of a misnomer these days. It is simply a mechanism for making HTTP requests and retrieving the data returned, it doesn't have to be XML. It can be plain text, (non X)HTML, JSON, anything. In fact, I don't think I've seen anything in the wild return actual XML data for an XMLHttpRequest in a very long time.
I have some jquery/php interaction set up on a page. It submits some data to the server and gets back records of data which are then to be aligned on the page for comparison and possible action beyond that.
My question is what is the best practice for returning the info and then displaying it?
Return JSON object and then create
html on the fly with js and display
the data?
Return JSON object and then
put that data in already created
containers for the data on the page?
Return pure html from the server and
just put that on the page?
I was rolling these through my head last night and couldn't really figure out if one way would be better for any particular reason.
I'm not a js guru so wasn't really sure the pros/cons and caveats to these different methods.
I think it ends up depending on your app.
Pure HTML is the easiest, you just drop in in place and viola. JQuery makes it a breeze to add the proper events and what not.
However, whenever I've used AJAX it's always evolved into returning JSON and building elements on the fly. If you are populating a tree for example, it may become messy to get the proper nesting. This forces you to have to do client side code anyway at which point simply using JSON from the start is cleaner.
Also, If you plan to use the data calls from other pages then using JSON is the way to go because the HTML will bee fixed.
This completely depends on the way you have things set up in your application. I, for one, prefer to return JSON (second approach in your list), because I have an 'error code' parameter that I check in onSuccess function before updating the content on the page, and if it's not zero then I notify the user of the error, including the error message that came back from the server (server-side validation, database timeout, etc.).
I think you're missing a perfectly valid option, one which I use often. This is my typical schema and it has yet to fail me... :-)
Here's the basic jQuery template I use:
$(function() {
$.getJSON('/some/page',{foo:bar,bar:foo},function(json) {
if(json.outcome == 'success') {
$('body').prepend(json.html);
} else {
// Somehow let the user know why it didn't work
alert(json.error);
}
});
});
Here's the basic backend (PHP in my case) structure I use:
<?php // Page: '/some/page'
/* Blah Blah Blah... do whatever needs to be done... */
// If everything turns out okay (assuming '$output' is the HTML
// you want to display...
echo json_encode(array('outcome'=>'success','html'=>$output));
// If something goes wrong... just do:
echo json_encode(array('outcome'=>'error','error'=>'Uh oh... something is broken'));
Naturally, you'll want to be more specific with your error by putting them into some variable or something. But, you should get the idea. Also, of course you can add more information to the json output. You can have some pre-made HTML and also some other information like a 'success notice' or a new class name for some element, I dunno... whatever... the possibilities are endless.
Anyways, the reason I choose this route is because it's usually faster (based on my experience) to append pre-made HTML to the DOM rather than looping over JSON and inserting the stuff unless it's just, like, a bit of text to replace into an element. But, the method I've shown is, IMO, the best of both worlds. You can attach HTML as a string to one of the JSON properties.
Happy jQuerying :-)
The "possible action beyond that" part of your question makes a big difference. If you need to do other things with the data besides display it, returning as JSON is a clearly better option because you can work with the data as a native JavaScript object instead of having to traverse the HTML DOM. If all you ever intend to do is display it, I don't see any reason to go through the trouble of building that display in JavaScript; just build the HTML in your presentation layer on the server.
This came up recently and possible a dupe: The AJAX response: Data (JSON, XML) or HTML snippet?.
If you are going to be creating HTML then you may as well be returning HTML directly and inject it into the DOM. However, there are times you need to work with objects which is where JSON comes in handy.
If you return a Person object for example then you can greet Person.Name and show Person.Preferences which is really handy. It depends on your design but the general considerations should be to keep HTML out of Javascript unless you're building RIA.
I have used all three and have come to the conclusion that returning HTML is better when introducing new elements to a page.
My experiance is that when building HTML with javascript I am usually replicating work that will have already have been done for the non javascript user journey.
I still prefer parsing json for updating existing elements or creating javascript only functionality. I tell myself this for bandwidth, but I think it just because I love javascript.
As a forth option, I read a great post about how Flickr deal with vast quantities of data with string concatination. Basically just parse a big o' string down the pipe and chop it up on the client. This significantly reduces the on the server, with only a marginal increase on the client.
Returning pure HTML is the best solution. For the most part gzip should neutralize any difference in bandwidth, and rendering via javascript on the client can be slow if the client is a crappy machine. Finally, writing javascript to render HTML is hard to work with compared to using something nice like a view if you use MVC.