It prevents disclosure of the response through JSON hijacking.
In theory, the content of HTTP responses is protected by the Same Origin Policy: pages from one domain cannot get any pieces of information from pages on the other domain (unless explicitly allowed).
An attacker can request pages on other domains on your behalf, e.g. by using a <script src=...>
or <img>
tag, but it can't get any information about the result (headers, contents).
Thus, if you visit an attacker's page, it couldn't read your email from gmail.com.
Except that when using a script tag to request JSON content, the JSON is executed as JavaScript in an attacker's controlled environment. If the attacker can replace the Array or Object constructor or some other method used during object construction, anything in the JSON would pass through the attacker's code, and be disclosed.
Note that this happens when the JSON is executed as JavaScript, not when it's parsed.
There are multiple countermeasures:
Making sure the JSON never executes
By placing a while(1);
statement before the JSON data, Google ensures that the JSON data is never executed as JavaScript.
Only a legitimate page could actually get the whole content, strip the while(1);
, and parse the remainder as JSON.
Things like for(;;);
have been seen on Facebook for instance, with the same results.
Making sure the JSON is not valid JavaScript
Similarly, adding invalid tokens before the JSON, like &&&START&&&
, makes sure that it is never executed.
Always return JSON with an Object on the outside
This is OWASP recommended way to protect from JSON hijacking and is the less intrusive one.
Similarly to the previous counter-measures, it makes sure that the JSON is never executed as JavaScript.
A valid JSON object, when not enclosed by anything, is not valid in JavaScript, since the { }
gets interpreted as a code block:
eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :
This is however valid JSON:
JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}
So, make sure you always return an Object at the top level of the response and make sure that the JSON is not valid JavaScript, while still being valid JSON.
As noted by @hvd in the comments, the empty object {}
is valid JavaScript, and knowing the object is empty may itself be valuable information.
Comparison of the above methods
The OWASP way is less intrusive, as it needs no client library changes, and transfers valid JSON. It is unsure whether past or future browser bugs could defeat this, however. As noted by @oriadam, it is unclear whether data could be leaked in a parse error through an error handling or not (e.g. window.onerror).
Google's way requires a client library in order for it to support automatic de-serialization and can be considered to be safer with regard to browser bugs.
Both methods require server-side changes in order to avoid developers accidentally sending vulnerable JSON.
)]}'
now instead ofwhile(1);
? Would the answers be the same? – Haase)]}'
may also be to save bytes, like facebook usedfor(;;);
which saves one byte :) – Hemimorphic