202

Possible Duplicate:
Why do people put code like “throw 1; <dont be evil>” and “for(;;);” in front of json responses?

I found this kind of syntax being used on Facebook for Ajax calls. I'm confused on the for (;;); part in the beginning of response. What is it used for?

This is the call and response:

GET http://0.131.channel.facebook.com/x/1476579705/51033089/false/p_1524926084=0

Response:

for (;;);{"t":"continue"}
Community
  • 1
  • 1
Mridul Kashatria
  • 4,109
  • 2
  • 16
  • 15
  • Interesting question. I wonder how they interpret the data though. Just get rid of the `for(;;);` and parse the result? – Luca Matteis Aug 17 '11 at 14:07
  • I'm not going to merge with the dupe because whilst they are about the same topic, the answers from this question won't fit just so nicely. – Kev Jul 21 '12 at 23:26
  • I'm really frustrated that the three answers with the most upvotes are wrong. Yet, the questions that this is a duplicate of have correct answers. This is simply and plainly spreading misinformation. It's even more frustrating because saurik is pretty much famous and the other two have reputations in the thousands. – gengkev Feb 19 '16 at 02:19

5 Answers5

157

I suspect the primary reason it's there is control. It forces you to retrieve the data via Ajax, not via JSON-P or similar (which uses script tags, and so would fail because that for loop is infinite), and thus ensures that the Same Origin Policy kicks in. This lets them control what documents can issue calls to the API — specifically, only documents that have the same origin as that API call, or ones that Facebook specifically grants access to via CORS (on browsers that support CORS). So you have to request the data via a mechanism where the browser will enforce the SOP, and you have to know about that preface and remove it before deserializing the data.

So yeah, it's about controlling (useful) access to that data.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • 1
    Thanks for answering T.J Crowder. I'm not clear about the need to defeat attempts to deserialize, how does it help in security and what kind of attack it prevents? – Mridul Kashatria Jun 14 '11 at 06:34
  • 9
    @mridkash: The only thing I can think of is that they don't want people using that API via JSON-P, which uses `script` tags to get around the Same Origin Policy. Also, they apparently only want the result consumed by someone who knows about the `for` loop, since of course that will break any standard JSON decoder (and in a really mean way if the decoder relies on `eval`). So that API is useless except when retrieved via ajax, and by someone who knows to remove that preface. Perhaps it's meant to only be used by their client-side code and they change the marker periodically... – T.J. Crowder Jun 14 '11 at 06:38
  • @mridkash using the eval function to parse some JSON, will execute any javascript code that is in the data without any checks, so if i give you a script which e.g. downloads a suspecious file, this javascript would be loaded on the clients computer, and that is clearly a security issue. – Yet Another Geek Jun 14 '11 at 06:39
  • That is pretty interesting as I'm also looking for a way to load JSON data from separate cached domain (AWS cloudfront) and this technique might help prevent misuse of personal data. – Mridul Kashatria Jun 14 '11 at 06:49
  • 4
    @mridkash: Yeah, but remember it only controls misuse of the data *via a web browser*. Anyone who wants to can get the data manually, or use a non-browser-based tool to retrieve the text and use it in an automated process (even create a reflector that strips off the prefix). So it's not like it's really secure, just making it awkward for people. And a reflector would eventually show up in your logs as a conspicuously active client. :-) – T.J. Crowder Jun 14 '11 at 06:55
  • 1
    Why not use `/*` as the prefix? – dave1010 Aug 17 '11 at 11:33
  • 1
    @dave: Indeed, though there's always the possibility some string in the data has the requisite `*/`. The `for(;;);` serves a deterrent role by locking things up for a while and then causing the browser to show a script busy/timeout error. – T.J. Crowder Aug 17 '11 at 12:20
  • I'm confused. You can't read the content of a remote script in a ` – Matchu Aug 17 '11 at 15:57
  • 1
    @Matchu: Agreed, even in raw form without the `for(;;);`, if you used a `script` element, the interpreter would interpret the object expression but not store the result anywhere, which wouldn't be useful. I think the `for(;;);` is primarily for discouraging people through causing the unfortunate effect, but we'd have to ask Facebook to be sure. (BTW, did this question just get linked somewhere? Suddenly all sorts of activity on it.) – T.J. Crowder Aug 17 '11 at 16:02
  • Yes, it got linked on [reddit](http://www.reddit.com/r/programming/comments/jlghf/) – kindall Aug 17 '11 at 17:10
  • 7
    @Crowder: In older browsers one can override the Array() function in ways that allow you to catch the data that is passed. This means that you can't always assume that JSON literals evaluated in script tags don't leak. – Clueless Aug 18 '11 at 00:15
  • 1
    Without the comment from @Clueless, this is only half an answer, as Mark Amery says on another question: http://stackoverflow.com/a/2669720/689161. As for unfortunate effects, there are none to prevent: accidentally including a JSON file with a ` – gengkev Feb 19 '16 at 02:43
  • [it seems that FB is no longer doing it](https://stackoverflow.com/questions/55206306/is-facebook-suddenly-safe-against-json-hijacking). I don't know why. They used to do it with `{..}` ( and still doing it partially). Regarding `[]` , I understand. Regarding `{..}` - I Don't – Royi Namir Mar 17 '19 at 16:42
107

Facebook has a ton of developers working internally on a lot of projects, and it is very common for someone to make a minor mistake; whether it be something as simple and serious as failing to escape data inserted into an HTML or SQL template or something as intricate and subtle as using eval (sometimes inefficient and arguably insecure) or JSON.parse (a compliant but not universally implemented extension) instead of a "known good" JSON decoder, it is important to figure out ways to easily enforce best practices on this developer population.

To face this challenge, Facebook has recently been going "all out" with internal projects designed to gracefully enforce these best practices, and to be honest the only explanation that truly makes sense for this specific case is just that: someone internally decided that all JSON parsing should go through a single implementation in their core library, and the best way to enforce that is for every single API response to get for(;;); automatically tacked on the front.

In so doing, a developer can't be "lazy": they will notice immediately if they use eval(), wonder what is up, and then realize their mistake and use the approved JSON API.

The other answers being provided seem to all fall into one of two categories:

  1. misunderstanding JSONP, or
  2. misunderstanding "JSON hijacking".

Those in the first category rely on the idea that an attacker can somehow make a request "using JSONP" to an API that doesn't support it. JSONP is a protocol that must be supported on both the server and the client: it requires the server to return something akin to myFunction({"t":"continue"}) such that the result is passed to a local function. You can't just "use JSONP" by accident.

Those in the second category are citing a very real vulnerability that has been described allowing a cross-site request forgery via tags to APIs that do not use JSONP (such as this one), allowing a form of "JSON hijacking". This is done by changing the Array/Object constructor, which allows one to access the information being returned from the server without a wrapping function.

However, that is simply not possible in this case: the reason it works at all is that a bare array (one possible result of many JSON APIs, such as the famous Gmail example) is a valid expression statement, which is not true of a bare object.

In fact, the syntax for objects defined by JSON (which includes quotation marks around the field names, as seen in this example) conflicts with the syntax for blocks, and therefore cannot be used at the top-level of a script.

js> {"t":"continue"}
typein:2: SyntaxError: invalid label:
typein:2: {"t":"continue"}
typein:2: ....^

For this example to be exploitable by way of Object() constructor remapping, it would require the API to have instead returned the object inside of a set of parentheses, making it valid JavaScript (but then not valid JSON).

js> ({"t":"continue"})
[object Object]

Now, it could be that this for(;;); prefix trick is only "accidentally" showing up in this example, and is in fact being returned by other internal Facebook APIs that are returning arrays; but in this case that should really be noted, as that would then be the "real" cause for why for(;;); is appearing in this specific snippet.

GMK
  • 2,480
  • 2
  • 17
  • 23
Jay Freeman -saurik-
  • 1,764
  • 1
  • 13
  • 13
  • This should be marked as the correct answer. The "for(;;);" prefix is most likely added as a byproduct of fixing the Array constructor remapping vulnerability. – David H Aug 18 '11 at 05:51
  • 16
    **It makes no sense that `for(;;);` would be used to prohibit `eval`.** There are much better ways for Facebook to control its own code. And `for(;;);` breaks all JSON parsers, including `eval`, equally. Developers must remove it manually in any case, but that hardly prevents `eval`. The answer is JSON hijacking attempts. Yes, object literals alone are invalid, but it's much easier and less error-prone to just insert (and later remove) `for(;;)` in front of all JSON, than to use conditional statements. – gengkev Feb 19 '16 at 02:04
45

Well the for(;;); is an infinite loop (you can use Chrome's JavaScript console to run that code in a tab if you want, and then watch the CPU-usage in the task manager go through the roof until the browser kills the tab).

So I suspect that maybe it is being put there to frustrate anyone attempting to parse the response using eval or any other technique that executes the returned data.

To explain further, it used to be fairly commonplace to parse a bit of JSON-formatted data using JavaScript's eval() function, by doing something like:

var parsedJson = eval('(' + jsonString + ')');

...this is considered unsafe, however, as if for some reason your JSON-formatted data contains executable JavaScript code instead of (or in addition to) JSON-formatted data then that code will be executed by the eval(). This means that if you are talking with an untrusted server, or if someone compromises a trusted server, then they can run arbitrary code on your page.

Because of this, using things like eval() to parse JSON-formatted data is generally frowned upon, and the for(;;); statement in the Facebook JSON will prevent people from parsing the data that way. Anyone that tries will get an infinite loop. So essentially, it's like Facebook is trying to enforce that people work with its API in a way that doesn't leave them vulnerable to future exploits that try to hijack the Facebook API to use as a vector.

aroth
  • 51,522
  • 20
  • 132
  • 168
  • Thanks for answering aroth. So it means that it is there for security purpose? However, I'm not clear about what kind of security hack it is supposed to defeat. – Mridul Kashatria Jun 14 '11 at 06:35
  • @mridkash - I added a bit to the answer, I hope that explains things a bit better for you. – aroth Jun 14 '11 at 06:46
  • That sure is interesting stuff. A bit like preparing for zombie attacks :), just kidding. I need to study more about JSON exploits as many web apps rely on it and there might be security vulnerabilities unknown to me. Thanks for the insight. – Mridul Kashatria Jun 14 '11 at 07:00
  • 5
    But `JSON.parse('for (;;);{"t":"continue"}')` breaks (SyntaxError), which is the secure way of parsing Json in Javascript. – Blaise Aug 17 '11 at 11:43
  • @BlaiseKal That's why, to parse this, you'll use something like `JSON.parse( 'for (;;);{"t":"continue"}'.substring(9) )`. – Arda Xi Aug 17 '11 at 13:02
  • 1
    But then, wouldn't it be just as easy to `eval('for (;;);{"t":"continue"}'.substring(9))`? – Alex J Aug 17 '11 at 13:28
  • @aroth Wasn't the initial appeal of JSON over XML that it was native JavaScript and could be parse with just `eval`? Now one needs to use a library with leaves the benefit of JSON a slightly smaller foot print that for most sites won't matter. – Sled Aug 17 '11 at 15:29
  • This answer is wrong, why does it have tons of upvotes? If you have the string in a variable so you can eval it you can just as easy substring it. Besides, eval is the way to do Json.parse in IE(before 9). T.J Crowder has the right answer. – aero Aug 17 '11 at 18:48
  • 1
    @aero - Please explain exactly what you think is wrong with it. `for(;;);` is in fact an infinite loop. If you're not expecting this and you try to `eval()` it, then your `eval()` will never return. This could have been instituted as a site-wide policy to prevent internal developers from carelessly using `eval()` to parse the results of asynchronous API calls. In any case, both answers include valid and different points. It's not a case of one being exactly right, and all others being wrong. – aroth Aug 18 '11 at 00:20
  • @aroth No, this answer is completely wrong. As others have pointed out, both `eval` and `JSON.parse` fail equally well when encountering `for(;;);`, and both are just as easily fixed with `.substring(9)`. Thus, there is no reason why this would discourage the use of `eval`. – gengkev Feb 19 '16 at 02:18
18

I'm a bit late and T.J. has basically solved the mystery, but I thought I'd share a great paper on this particular topic that has good examples and provides deeper insight into this mechanism.

These infinite loops are a countermeasure against "Javascript hijacking", a type of attack that gained public attention with an attack on Gmail that was published by Jeremiah Grossman.

The idea is as simple as beautiful: A lot of users tend to be logged in permanently in Gmail or Facebook. So what you do is you set up a site and in your malicious site's Javascript you override the object or array constructor:

function Object() {
    //Make an Ajax request to your malicious site exposing the object data
}

then you include a <script> tag in that site such as

<script src="http://www.example.com/object.json"></script>

And finally you can read all about the JSON objects in your malicious server's logs.

As promised, the link to the paper.

emboss
  • 36,575
  • 7
  • 93
  • 103
13

This looks like a hack to prevent a CSRF attack. There are browser-specific ways to hook into object creation, so a malicious website could use do that first, and then have the following:

<script src="http://0.131.channel.facebook.com/x/1476579705/51033089/false/p_1524926084=0" />

If there weren't an infinite loop before the JSON, an object would be created, since JSON can be eval()ed as javascript, and the hooks would detect it and sniff the object members.

Now if you visit that site from a browser, while logged into Facebook, it can get at your data as if it were you, and then send it back to its own server via e.g., an AJAX or javascript post.

Carles Alcolea
  • 7,984
  • 4
  • 30
  • 51
Jason
  • 1,001
  • 9
  • 13
  • Any examples or links about hooking into object creation? Can't find anything with a quick Google search. – dave1010 Aug 17 '11 at 11:31
  • 1
    @dave1010 Being able to hook into *array* creation is a known security issue in most browsers. There is no such issue with objects, however. This is why a common anti-CSRF technique when returning arrays in JSON is to wrap the array in another object. – Alan Plum Aug 17 '11 at 11:43
  • @Alan, yeah, I knew of redefining `Array` as a function to get at created arrays. As there isn't a way to do this for objects, is there actually any need for the `for(;;);` prefix? – dave1010 Aug 17 '11 at 11:54
  • 2
    @dave1010 Array literals are valid JSON. It's a lot more obvious and less error-prone to force CSRF protection on everyone than to hope that whoever is constructing JSON responses knows that top-level arrays are a CSRF hole. – Clueless Aug 18 '11 at 00:13
  • @Clueless that's a good point. I guess `for(;;);` isn't required if you're sure you know what you're doing and will always control the JSON format. – dave1010 Aug 18 '11 at 09:40