JSON Hijacking

0 comments suggest edit

A while back I wrote about a subtle JSON vulnerability which could result in the disclosure of sensitive information. That particular exploit involved overriding the JavaScript Array constructor to disclose the payload of a JSON array, something which most browsers do not support now.

However, there’s another related exploit that seems to affect many more browsers. It was brought to my attention recently by someone at Microsoft and Scott Hanselman and I demonstrated it at the Norwegian Developers Conference last week, though it has been demonstrated against Twitter in the past.


Before I go further, let me give you the punch line first in terms of what this vulnerability affects.

This vulnerability requires that you are exposing a JSON service which…

  • …returns sensitive data.
  • …returns a JSON array.
  • …responds to GET requests.
  • …the browser making the request has JavaScript enabled (very likely the case)
  • …the browser making the request supports the __defineSetter__ method.

Thus if you never send sensitive data in JSON format, or you only send JSON in response to a POST request, etc. then your site is probably not vulnerable to this particular vulnerability (though there could be others).

I’m terrible with Visio, but I thought I’d give it my best shot and try to diagram the attack the best I could. In this first screenshot, we see the unwitting victim logging into the vulnerable site, and the vulnerable site issues an authentication cookie, which the browser holds onto.


At some point, either in the past, or the near future, the bad guy spams the victim with an email promising a hilariously funny video of a hamster on a piano.


But the link actually points to the bad guy’s website. When the victim clicks on the link, the next two steps happen in quick succession. First, the victim’s browser makes a request for the bad guy’s website.


The website responds with some HTML containing some JavaScript along with a script tag. When the browser sees the script tag, it makes another GET request back to the vulnerable site to load the script, sending the auth cookie along.


The bad guy has tricked the victim’s browser to issue a request for the JSON containing sensitive information using the browser’s credentials (aka the auth cookie). This loads the JSON array as executable JavaScript and now the bad guy has access to this data.

To gain a deeper understanding, it may help to see actual code (which you can download and run) which demonstrates this attack.

Note that the following demonstration is not specific to ASP.NET or ASP.NET MVC in any way, I just happen to be using ASP.NET MVC to demonstrate it. Suppose the Vulnerable Website returns JSON with sensitive data via an action method like this.

public JsonResult AdminBalances() {
  var balances = new[] {
    new {Id = 1, Balance=3.14}, 
    new {Id = 2, Balance=2.72},
    new {Id = 3, Balance=1.62}
  return Json(balances);

Assuming this is a method of HomeController, you can access this action via a GET request for /Home/AdminBalances which returns the following JSON:


Notice that I’m requiring authentication via the AuthorizeAttribute on this action method, so an anonymous GET request will not be able to view this sensitive data.

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.

Now let’s look at the HTML page that the bad guy hosts on his/her own server:

    <script type="text/javascript"> 
        Object.prototype.__defineSetter__('Id', function(obj){alert(obj);});
    <script src="http://example.com/Home/AdminBalances"></script> 

What’s happening here? Well the bad guy is changing the prototype for Object using the special __defineSetter__ method which allows overriding what happens when a property setter is being called.

In this case, any time a property named Id is being set on any object, an anonymous function is called which displays the value of the property using the alert function. Note that the script could just as easily post the data back to the bad guy, thus disclosing sensitive data.

As mentioned before, the bad guy needs to get you to visit his malicious page shortly after logging into the vulnerable site while your session on that site is still valid. Typically a phishing attack via email containing a link to the evil site does the trick.

If by blind bad luck you’re still logged into the original site when you click through to the link, the browser will send your authentication cookie to the website when it loads the script referenced in the script tag. As far as the original site is concerned, you’re making a valid authenticated request for the JSON data and it responds with the data, which now gets executed in your browser. This may sound familiar as it is really a variant of a Cross Site Request Forgery (CSRF) attack which I wrote about before.

If you want to see it for yourself, you can grab the CodeHaacks solution from GitHub and run the JsonHijackDemo project locally (right click on the project and select Set as StartUp Project. Just follow the instructions on the home page of the project to see the attack in action. It will tell you to visit http://demo.haacked.com/security/JsonAttack.html.

Note that this attack does not work on IE 8 which will tell you that __defineSetter__ is not a valid method. Last I checked, it does work on Chrome and Firefox.

The mitigation is simple. Either never send JSON arrays OR always require an HTTP POST to get that data (except in the case of non-sensitive data in which case you probably don’t care). For example, with ASP.NET MVC, you could use the AcceptVerbsAttribute to enforce this like so:

public JsonResult AdminBalances() {
  var balances = new[] {
    new {Id = 1, Balance=3.14}, 
    new {Id = 2, Balance=2.72},
    new {Id = 3, Balance=1.62}
  return Json(balances);

One issue with this approach is that many JavaScript libraries such as jQuery request JSON using a GET request by default, not POST. For example, $.getJSON issues a GET request by default. So when calling into this JSON service, you need to make sure you issue a POST request with your client library.

ASP.NET and WCF JSON service endpoints actually wrap their JSON in an object with the “d” property as I wrote about a while back. While it might seem odd to have to go through this property to get access to your data, this awkwardness is eased by the fact that the generated client proxies for these services strip the “d” property so the end-user doesn’t need to know it was ever there.

With ASP.NET MVC (and other similar frameworks), a significant number of developers are not using client generated proxies (we don’t have them) but instead using jQuery and other such libraries to call into these methods, making the “d” fix kind of awkward.

What About Checking The Header?

Some of you might be wondering, “why not have the JSON service check for a special header such as the X-Requested-With: XMLHttpRequest or Content-Type: application/json before serving it up in response to a GET request?” I too thought this might be a great mitigation because most client libraries send one or the other of these headers, but a browser’s GET request in response to a script tag would not.

The problem with this (as a couple of co-workers pointed out to me) is that at some point in the past, the user may have made a legitimate GET request for that JSON in which case it may well be cached in the user’s browser or in some proxy server in between the victim’s browser and the vulnerable website. In that case, when the browser makes the GET request for the script, the request might get fulfilled from the browser cache or proxy cache. You could try setting No-Cache headers, but at that point you’re trusting that the browser and all proxy servers correctly implement caching and that the user can’t override that accidentally.

Of course, this particular caching issue isn’t a problem if you’re serving up your JSON using SSL.

The real issue?

There’s a post at the Mozilla Developer Center which states that object and array initializers should not invoke setters when evaluated, which at this point, I tend to agree with, though a comment to that post argues that perhaps browsers really shouldn’t execute scripts regardless of their content type, which is also a valid complaint.

But at the end of the day, assigning blame doesn’t make your site more secure. These type of browser quirks will continue to crop up from time to time and we as web developers need to deal with them. Chrome and Firefox 3.0.11 were both vulnerable to this. IE 8 was not because it doesn’t support this method. I didn’t try it in IE 7 or IE 6.

It seems to me that to be secure by default, the default behavior for accessing JSON should probably be POST and you should opt-in to GET, rather than the other way around as is done with the current client libraries. What do you think? And how do other platforms you’ve worked with handle this? I’d love to hear your thoughts.

In case you missed it, here are the repro steps again: grab the CodeHaacks solution from GitHub and run the JsonHijackDemo project locally (right click on the project and select Set as StartUp Project. Just follow the instructions on the home page of the project to see the attack in action. To see a successful attack, you’ll need to do this in a vulnerable browser such as Firefox 3.0.11.

I followed up this post with a proposal to fix JSON to prevent this particular issue.

Tags: aspnetmvc, json, javascript, security, browsers

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.



78 responses

  1. Avatar for Scott
    Scott June 25th, 2009

    So, IE "whatever's next" will include support for getters and setters.

  2. Avatar for David Radcliffe
    David Radcliffe June 25th, 2009

    So, if I return my array inside a json object, I should be ok? Regardless of GET or POST?

  3. Avatar for Jon Freeland
    Jon Freeland June 25th, 2009

    Thanks for this, very informative!

  4. Avatar for Mike Simpson
    Mike Simpson June 25th, 2009

    Thanks for the great post - very informative. This seems to be somewhat more of an issue for RESTful sites, since using POST instead of GET may not be a good option. But avoiding sending arrays, or wrapping them in an object property, are both useful workarounds.

  5. Avatar for Louis DeJardin
    Louis DeJardin June 25th, 2009

    I have some actions which return Json(...) if IsAjaxRequest() otherwise they return a view or redirect. So an unconditional POST-only on those actions would be too restrictive.
    Would you agree something like an [AjaxRequiresPost] attribute avoids the vulnerability?
    public class AjaxRequiresPostAttribute :
    public override bool IsValidForRequest(
    ControllerContext controllerContext,
    MethodInfo methodInfo)
    var request = controllerContext.HttpContext.Request;
    if (request.IsAjaxRequest() &&
    string.Equals(request.HttpMethod, "POST") == false)
    return false;
    return true;

  6. Avatar for LukCAD
    LukCAD June 25th, 2009

    Thank you, Haacked, very important notes about jSon. But we will never found now sites where javascript not used. Controls from ASP.NET in big cases also use javascript libraries for generating events from client side. You are right that ASP.NET has better security and more reliable then MVC, but i must note that sometime error (mistake) of security is into wrong adjusting of web servers. Image next: if somebody has asp.net site into root site with just only asp technology - then not any grantee that asp code easy to use to hijack strong security from asp.net(note: it will works like inserted by json javascripts but more worst - on server side).
    My resume: problem not with technology of sending objects - problem how and where it must be used. JSON is good for news feed and for chat objects. JSON is bad for transmitting in banking, servicing and accounting systems where databases save a lot of records about providers and subscribers.
    But i hope your article will help a lot of CEO find a right way for the web technology and do not a lot of changing every year regards of modern words in press. step by step we need use reliable technology and with maximal profit and faster and faster experiment with new ideas around.
    Sincerely, LukCAD

  7. Avatar for Stuart Branham
    Stuart Branham June 25th, 2009

    @David - With regards to this particular vulnerability, it sounds like it. That's what Phil described ASP.NET and WCF as doing with the automatic { d: [] } construct.

  8. Avatar for Haacked
    Haacked June 25th, 2009

    @David that is correct, as Stuart points out. The vulnerability only applies if the JSON package you send IS a JSON array.
    @Louis well one thought is we change JsonResult to require POST by default. That way, you wouldn't need to change your action method. However, if we did that, then jQuery calls for JSON data would have to be updated to specify that the HTTP method to use should be POST and not GET, which is the default.

  9. Avatar for Louis
    Louis June 25th, 2009

    Sounds good. I was thinking briefly you would still be exposed to state changes committed before for JsonResult throws, but that's moot because it's true for any script src where the target doesn't have AcceptVerbs POST.
    So +1 on require POST by JsonResult. Or possibly only require POST when you attempt to return an array? It would be less impactful - unless that leaves other vulnerability concerns.

  10. Avatar for Haacked
    Haacked June 25th, 2009

    I personally like that approach, but the worry is that there may be other similar exploits we haven't discovered yet. The tendency over here is to try to avoid such heuristics when it comes to security.
    Also, it can get confusing when the JSON in some cases works and others doesn't and the end user doesn't understand why.
    Eilon has a phrase he likes to tell me. "Heuristic" is another word for "Bug". ;)

  11. Avatar for David Meyer
    David Meyer June 25th, 2009

    Another thing to think about, which probably isn't an issue in this case, is that POST is by definition non-deterministic, meaning that it is never cached. This might affect performance, but it seems like these types of GET requests would probably be non-deterministic anyway. Just a thought.
    The best solution would be, of course, to make everyone smart enough not to click on the bad guy's link. :P
    Don't you hate how security and permissions issues eat up our valuable time??? Thanks for the heads up, though!

  12. Avatar for Thanigainathan.S
    Thanigainathan.S June 25th, 2009

    Hi Sir,
    This article is very helpful for me.

  13. Avatar for Asbj&#248;rn Ulsberg
    Asbj&#248;rn Ulsberg June 25th, 2009

    I have a fairly simple solution to mitigate this problem without requiring POST or some other obscure (and wrong) HTTP method to access the JSON data. Most Ajax libraries, when accessing JSON, request it with 'Accept: appliaction/json'. They also append the HTTP header 'X-Requested-With: XMLHttpRequest'.
    If both of these headers were added up as requirements to access the JSON data (on top of Authorize), a simple HTML script reference to the AdminBalances JsonResult Action wouldn't work. My humble opinion is that promoting POST as a solution to problem this is misguided and is like forcing a screw in with a hammer.

  14. Avatar for Sruly Taber
    Sruly Taber June 25th, 2009

    Thanks for the info.
    It kinda feels wrong to use POST to GET data.
    Hopefully the browser will fix this vulnerability in the future.

  15. Avatar for zihotki
    zihotki June 25th, 2009

    What about to check referrer on the json request and send json data only to referrers in white list? It seems to me that this should work - as far as I remember there are no way to modify referrer for urls in script html element.

  16. Avatar for Andrew
    Andrew June 25th, 2009

    Good post. But where's the hamster on the piano?

  17. Avatar for Todd Price
    Todd Price June 25th, 2009

    Would SSL really solve anything? Wouldn't that just protect the data from being sniffed over the wire? Once it arrives at the browser, it will have been decrypted, and the hijacked setter will still have access to the data, no? Haven't actually tried it myself though. Anybody have an answer?

  18. Avatar for Haacked
    Haacked June 25th, 2009

    @Asbjørn as I pointed out in my post, that wouldn't work. Imagine this scenario. Step 1, you visit the vulnerable site and legitimately make a proper AJAX request. The site returns the JSON to your browser. Now your browser caches that JSON.
    Now, when you visit the bad guy site, the script tag tries to request that file, but the browser returns it from the cache! It doesn't even make a request to the bad server.
    In that case, your bad data has been returned.

  19. Avatar for Haacked
    Haacked June 25th, 2009

    @Todd I believe SSL *only* solves the caching issue because browsers are not supposed to cache SSL content. But I could be wrong.

  20. Avatar for Haacked
    Haacked June 25th, 2009

    @zihotki see my response to Asbjørn. Any solution that requires checking headers etc... is still vulnerable because you're allowing the browser to cache this sensitive data.
    At some point, the user will visit the site, and make a legitimate request and cache the data, after all, that's the whole point of the JSON service.
    Once the data is in the browser cache, it's vulnerable to this attack. You can't force the browser check for these headers in the same way that your server does.
    Keep in mind, it might not even be your browser that serves up the content. Maybe it's an intermediate proxy server. Relying on checking for headers is not safe in this case.

  21. Avatar for Asbj&#248;rn Ulsberg
    Asbj&#248;rn Ulsberg June 25th, 2009

    @Haacked: You're correct with your caching scenario, but what if we force the browser not to cache the response in the first place? It will still be better than using POST to GET something, imho.

  22. Avatar for Andrey Shchekin
    Andrey Shchekin June 25th, 2009

    Would this work under IE8 if you use Object.defineProperty?

  23. Avatar for zihotki
    zihotki June 25th, 2009

    @Asbjørn there are no way to force browser or proxies not to cache something with 100% guarantee, Phil is right here. There may be bugs in proxies and browsers or superb optimizations. We can't absolutely guarantee that using "Pragma: No-cache;" or other techniques nothing will be cached.
    And I agree, the most easiest way to fix this is to use POST instead of GET.

  24. Avatar for Haacked
    Haacked June 25th, 2009

    @Asbjørn Browsers have a history of caching problems, bugs, etc... As Zihotki says, that would be relying on every browser from now and into the future to get this correct. Not only every browser, but every Proxy server.
    I'm not willing to lay my bet on that.
    One nice thing about requiring POST is that it protects ALL browsers, old and new. Only an untrusted browser would be prone to this issue, but if your browser is compromised, then all bets are off anyways. It might as well send keystrokes directly to the bad guy. ;)
    I also wrote about an alternative which would require everyone to change JSON itself. I have very little hope of seeing it happen, but it also has the benefit of suddenly closing the hole for old browsers.

  25. Avatar for drew
    drew June 26th, 2009

    I disagree with your argument that a custom header shouldn't be used because of misbehaving caches. If you're not disabling proxy caching for sensitive data, you're asking for trouble anyways. Disabling caching properly is a bit tricky, but there are some useful details here: code.google.com/.../Part2#Document_caching
    Perhaps there are some interesting corner-cases where the browser will locally cache the JSON. Time to go play with it...

  26. Avatar for Pat Gannon
    Pat Gannon June 26th, 2009

    My 2 cents is that I strongly disagree with this: "It seems to me that to be secure by default, the default behavior for accessing JSON should probably be POST and you should opt-in to GET".
    This is an abuse of HTTP (to use HTTP POST to GET data) and will disable scenarios where caching is desirable and will make your JSON method less compatible with generic AJAX components that are designed to work with any RESTful resource.
    I think that "chang[ing] JsonResult to require POST by default" is a bad idea. Not only are you making it making it so that accessing an MVC/JSON action via jQuery would require an extra bit of hacky code, you are also significantly reducing one of the advantages of ASP.NET MVC, which is that it is currently the best way (IMO) to make RESTful websites on the .NET platform. That is certainly one of the reasons that I give when folks ask me why they should use MVC.
    My vote, obviously, is NO on that solution. I think it would be better to put the responsibility of security on the developer (especially for a somewhat remote scenario like this given that the user has to click on a nefarious link AND be logged into a particular site that the attacker is targeting) and allow them to decide what solution is proper for this case (if any at all). I think in general web developers shouldn't be lulled into a false sense of security by using a framework which touts itself as being "secure by default".
    I'm a little confused about the alternative of putting your JSON in an object rather than an array. So will wrapping a JSON array in a top-level JSON object fix this, or will the vulnerability be present if there's an array anywhere in your JSON? If a top-level object fixes this, why doesn't the default top-level "d" property you mentioned solve the issue? If any solution along these lines is possible, I would think that would be highly preferable to the POST hack. ;-)
    Take care, and keep up the good work! I'm really loving this MVC stuff! :-)
    Pat Gannon

  27. Avatar for Haacked
    Haacked June 26th, 2009

    @Pat Hey Pat! Long time no hear. :)
    I understand the pain this change would cause. I don't like it either, but I disagree with your assessment for several reasons.
    First of all, read through the comments on this post and the follow-up post to this. Notice that even very smart developers are having trouble fully grokking the issue.
    Your own comment shows a bit of misunderstanding. I answer your question in a comment on the follow-up post about why the "d" property solves it. Short answer, a JavaScript file that starts with "{" is not a valid script, so the browser throws a script error and the script does not continue to execute. Remember, this attack relies on requesting the script via the SCRIPT tag.
    Honestly, I think making JSONResult require POST, but with an option to override that behavior to allow GET for those who know what they are doing is the best option. Given that very few developers fully grok this bug, how can we expect them all to secure themselves? In the follow-up post, Douglas Crockford, the inventor of JSON, even condones this idea.
    You say this attack is obscure, but I linked to posts that showed that GMail and Twitter have all been struck by this in the past. After all, aren't you almost always logged into Gmail? Think about that, Google engineers got this wrong the first time. If they didn't get this right, how do you expect us mere mortals to get it right every time?
    Lastly, the jQuery code is not so hacky as you think. This guy wrote up a tiny jQuery example in no time.
    For those who want to allow GET for JSON arrays because they've got all these issues covered, we won't prevent that. I just don't think we should make that the default.

  28. Avatar for Artiom
    Artiom June 27th, 2009

    Another way to save your users is to use security tokens.
    For example, in ASP.NET MVC there's a special class to prevent CSRF attacks. It creates a cookie with a security token when you load the form, and when you submit the form the value submitted in the form is checked against the cookie. If course that works only in POST but that's good, right? :P
    See here for more details, and examples (not my blog btw)

  29. Avatar for Burcu Dogan
    Burcu Dogan July 1st, 2009

    Unfortunately a referrer check is not solving the problem since we cached the data once on the client. Once you let it to be cached it, it's not safe anymore. Re-authentication may work, but it is only possible on POST and POST's itself kills this headache. It'd absurd to create another subsystem to handle to do the rechecking. This sounds more like a problem of HTTP, rather than abused usage of cached material. Making JSON requests via POST by default is purely forcing the main design, so the decision should be left to developer such as trivial problems like SQL injections checks on other platforms.

  30. Avatar for Amit bajaj frm Fazilka INDIA
    Amit bajaj frm Fazilka INDIA July 16th, 2009

    hi, i m Amit Bajaj frm Punjab India.. Dis is very gud website..

  31. Avatar for Drake
    Drake July 19th, 2009

    I was reading the book Ajax Security and was wondering if the solution they offered would deter an attacker. They seem to imply that even enclosing in Object (instead of array) could be possibly hacked since you (may be?) able to override Object constructor as well ... and best solution was to add something to cause attackers page to go into an infinite loop (since javascript will be executed). That solution was to add something like for(;;); and strip that out on your site... but i was curiuos, can that also be used by the attacker aka not sure how this would work but ...
    the attacker used a ajax/json library to get json data, treats it as a string, strips out that 'for(;;)' if its there and passes it to <script> as src param or eval()'s it. Just guessing, kinda new to this security stuff.

  32. Avatar for Guest
    Guest December 14th, 2009

    I'm sorry, but I have some issues with the content of this post.
    1. You state that an object literal {id:"1", value:"foo"} is not valid JavaScript and if it's returned to a script tag will throw an error. This is completely false. 100%. Object literals are in fact the fundamental basis of JSON, which is perfectly valid JavaScript.
    2. You make no real explanation of why POST is safe but GET is not. I can only guess it's because you're asserting that a malicious site can't make an automatic/background cross-domain POST (where clearly they can make GETs via script tags).
    But sites certainly can make background POSTs, even cross domain, including iframe proxies, flash proxies (like flXHR), etc. So a POST seems just as vulnerable.
    I think the point of this article should be about the very familiar auth hijacking vulnerability. This really has nothing to do with JSON (in my opinion).

  33. Avatar for haacked
    haacked December 15th, 2009

    @Kyle regarding #1, prove it. Show me a JavaScript that is a valid JSON object literal for which the browser continues to execute the scirpt and does not throw an error.
    2. POST responses aren't cached by proxies or browsers. Do you have a demo of this? For the most part, POST is much safer than GET when you're using a trusted browser. If the browser is not trusted, then all bets are off. You have bigger problems then.

  34. Avatar for James Wheare
    James Wheare December 20th, 2009

    JSONP has this exact same vulnerability and is the reason why you should NEVER expose sensitive information via a valid JavaScript statement. Much has already been written on this subject.
    The ONLY safe way to return sensitive data is as an object literal on it's own. A JSONP callback is a valid JavaScript statement, just as an array literal sometimes is in some browsers.
    An assignment statement is also valid, you could have written a blog post about how it's a bad idea to return sensitive data like this:
    var pinNumber = "1234";
    This is the first I've seen anything returning JSON as an array, but maybe it's more common than I thought, I suppose it's technically valid JSON.
    For what it's worth, it looks like __defineSetter__ no longer works in the latest version of Firefox.

  35. Avatar for Freez
    Freez February 25th, 2010

    I can't download the demo project, the archive is broken

  36. Avatar for John
    John June 9th, 2010

    1. Thanks for this post.
    2. Thanks for the descriptive error in ASP.NET MVC 2. I wouldn't have known about this if it weren't for that exception. In general, I appreciate the attitude that "we should make them stop and think" but then also allow me to go ahead anyway via simple annotation.
    3. I wonder how impossible it would be to take the next logical step and include a link to a MS KB article in the server's response?

  37. Avatar for apple-laptop-battery
    apple-laptop-battery July 14th, 2010

    good article! thanks

  38. Avatar for saleh
    saleh July 26th, 2010

    is there any fiewall for json?
    is it reasonable to make a firewall for this purpose?

  39. Avatar for Pes 2011 Patch
    Pes 2011 Patch August 16th, 2010

    Thanks for useful information ..

  40. Avatar for the silk of the hustler
    the silk of the hustler September 23rd, 2010

    The acronym JSON (pronounced like the name “Jason”) stands for JavaScript Object Notation. It’s a way of annotating data that’s relatively easy for humans to read and write. This helps explain its recent popularity. As Ajax applications, which depend heavily on JavaScript, have become common, programmers have searched for an easy way to transfer data. Converting JSON to something usable in JavaScript takes one line of code and automatically works in all browsers.

  41. Avatar for shan mady
    shan mady September 30th, 2010

    I read the book Ajax Security and wondered if the proposed solution to deter an aggressor. They suggest that, even locked up in objects instead of paint because it could be hacked (maybe?) Able to overload the constructor of the object, and ... and the best solution was to add something because the site of the attackers to enter an infinite loop, because JavaScript runs.

  42. Avatar for Jordan
    Jordan October 27th, 2010

    Kudos haacked! It’s about time one knew that ASP.NET offers more security option compared to MVC. Thanks for that info and great work as well. But what happens when do not allow our browser to hoard responses wont that workout better than using POST to GET something?

  43. Avatar for Robert
    Robert November 21st, 2010

    It sounds like this security issue only occurs when a json call is made to an outside website? If our MVC2 app only makes json calls to our own website (to fill jqgrids for example), we should safely be able to override the Json method to always allow gets, correct?

  44. Avatar for Kul
    Kul January 27th, 2011

    Very nice article and good debate,
    Let me amuse you with more extreme thoughts (than using Post)...
    I think for for whatever it's worth , we should not use browsers at all and use specific containers for the business applications so that all vulnerabilities, hacks associated with browsers are dealt in single shot.
    Comparing this to a real-life scenario..when one withdraw big money from ATM/bank, then he/she prefers to travel in private vehicle rather than a shared/public transport. I am sure readers in US will not associate much with this. However, readers in India probably will. IMO, web security scenario is same in US & India w.r.t. # and type of vulnerabilities.
    With above being said, I think browsers will still make a good choice for informational websites (such as news) as well as a good vehicle to distribute business applications...
    Now whatever I have said above is only for new applications, changing existing applications to new containers will require tremendous amount of effort so will not advise for it...

  45. Avatar for Mauricio Szabo
    Mauricio Szabo February 15th, 2011

    Could not reproduce the error with Firefox 3.0.10, nor with chromium browser 11.0.665.0 (on Ubuntu) or Safari, on iPhone. Only with Midori I could reproduce the problem (but I don't think anybody uses this, so I believe I'm safe).

  46. Avatar for giri
    giri March 22nd, 2011

    hi , i have written a method in contoller which returns JSONResult
    "XML_F52E2B61-18A1-11d1-B105-00805F49916B": "<ViewFavFood FoodName=\"Pizza\" VolumeIntake=\"High\" Id=\"1\"/>"
    how to display the json string in my view

  47. Avatar for Cedd
    Cedd May 19th, 2011

    I'm currently busy with a RIA develoment.
    I came to this post as I wanted to make sure that I don't have any security problems.
    I'm currently bound to use MVC2 and VS2008 (damned employers...)
    So, according to the inforamtion in this post and in the alternative proposal, I'm actually safe and this from the first time I took on hijaxing the forms...
    This is merely due to a post (sorry, I don't remember which one and who is to grant for that) that was somehow questioning how to get json object returned with specific "attributes" or call the m properties...
    So this would leave the possibility to include the actual result(data), a message and a status.
    I was looking into some sort of same functionality in order to be able to perform client-side validation plus server-side validation and take appropriate actions depending on the validation results...
    SO it finally sort out that currently the application repsonses will look all similar to this :
    return Json(new
    status = 0,
    message = "You are Authenticated",
    data = RedirectUrl
    And as far as I understood the problem here, this response "template" is not opening the door to the bad guy.

  48. Avatar for William
    William September 21st, 2011

    I might be missing a trick here, but it seems to me that the underlying problem isn't JSON, but the fact that cookie data is used to validate the request to the JSON service.
    Clearly browser domain policies prevent the attackers website from directly accessing your website's cookie (hence this exploit). If you mandate that a JSON request requires the ability to directly read the cookie, then you have solved the problem.
    You restrict the JSON service to only accept the session-identifier (or whatever your secret is) as a parameter. Therefore to perform a JSON request you need to be able to: read your cookie, extract your session-identifier and send the session-identifier as a parameter in your GET/POST/XMLHTTPRequest. Since the hacker's website is not able to read your cookie directly, the loophole is closed.

  49. Avatar for Guest
    Guest January 20th, 2012

    See this answer: security.stackexchange.com/...
    "If the browser has a cookie for site A, it will include it in all requests to site A. This is true even if the request was triggered by a <script> tag on site B."
    Site B isn't able to read your cookie but the browser will send it along with the request.

  50. Avatar for Low Chin Chau
    Low Chin Chau April 14th, 2012

    A solution seems to be suggested in your article section "What About Checking The Header?". If the data is sensitive enough for this vulnerability to matter, you should be using SSL anyway.
    In short, if the server only responds to SSL and the correct headers, this vulnerability does not work. Am I missing something?

  51. Avatar for Jason
    Jason April 26th, 2012

    ok, so I've seen several methods - mostly unparseable crufts - sitepen.com/blog/2008/09/25... - to prevent this. However, I'm wondering if serving the json over SSL and always have a top level object prevents this issue. Most of the information surrounding this issue seems to be pre-2009. So for those of us that are wanting to keep our json secure, finding current methods and practices is challenging. Any insight you can offer would be great. Thanks.

  52. Avatar for Andy
    Andy December 21st, 2012

    The page at http://demo.haacked.com/security/JsonAttack.html. seems to not to be working anymore.
    Because the page makes a request to
    GET http://localhost:54607/Home/AdminBalances HTTP/1.1

  53. Avatar for Jim. D.
    Jim. D. January 12th, 2013

    it is you in the picture ? :)) 

  54. Avatar for joey
    joey January 15th, 2013

    now the bad guy has access to this data.

  55. Avatar for Michael B
    Michael B February 10th, 2013

    Link for should not invoke setters when evaluated is broken.

  56. Avatar for Amol Joshi
    Amol Joshi February 12th, 2013

    That's gr8..Thanks for this astounding article.It expains Json Hijacking concept very well.
    I have one question here in above scenario.

    I understand  the script referenced in in src tag gets executed with Json Array from server on the Victims browser, but can you please exaplain how the Bad guy will get access to this sensitive Json array ?
    Thanks in Advance.

  57. Avatar for balpha
    balpha February 20th, 2013

    I've found an exploit that's made possible by modern JavaScript magic that doesn't even require the response to be JSON: http://balpha.de/2013/02/pl...

    It's a fairly narrow case -- not as high-profile as the Array problem -- but it's somewhat similar.

  58. Avatar for haacked
    haacked February 20th, 2013

    Hey Ben! That's pretty freaking interesting! I think the lesson there is don't do that! Sending sensitive data via a  GET in any form is asking for trouble. It requires too much trust in every browser's JavaScript implementation now and in the future.

  59. Avatar for Om Shankar
    Om Shankar August 23rd, 2013

    How to parse such a JSON data when you are requesting from jQuery and want to end up in the success callback?

  60. Avatar for Vic1ouS
    Vic1ouS September 25th, 2013

    So, this is the reason why the REST social services (graph.facebook for
    example) returns arrays inside of a "data"-called object.. I mean
    suddenly that "data" wrapping seems like "convenient" coincidence, isn't

    I however still miss the point of why GET is vulnerable and
    POST isn't.. When the site sends request to the malicious site to load
    the script, what "magic" does POST have over GET to prevent sending the
    browser's "cookie ID" to the malicious site.. Do post-type requests not
    send that ID ?, what's the main difference ?

    // Sorry for being not-specific in professional terms a bit though

  61. Avatar for haacked
    haacked September 25th, 2013

    > So, this is the reason why the REST social services (graph.facebook for example) returns arrays inside of a "data"-called object

    Most likely! Great observation!

    > what "magic" does POST have over GET to prevent sending the browser's "cookie ID" to the malicious site.. Do post-type requests not
    send that ID ?, what's the main difference ?

    The "magic" is in not supplying a response to GET.

    The vulnerability relies on loading the JSON payload via a SCRIPT tag. A browser will never issue a POST to load the script referenced by the SCRIPT tag. It'll issue a GET. So if you don't respond with the JSON payload to GET requests, you mitigate this attack.

  62. Avatar for code[enabled]
    code[enabled] November 2nd, 2013

    to be frank i stiil don't get how you will be able to use the _definesetter_ given that there will be many objects on the page

  63. Avatar for sancoLgates
    sancoLgates October 13th, 2014

    thanks for the great post.

  64. Avatar for Agung Pambudi
    Agung Pambudi October 14th, 2014

    I am confusing....Could you help me to solving my problem...?

  65. Avatar for Tridip
    Tridip February 27th, 2015

    nice article but one question that a script may download from hacker side which will have jquery ajax function that use post mechanism to call mvc post action method which would return json array and i guess in that case auth cookie also will be transfer. so why you suggest to return json data for post action. how post can make it secure. it will be helpful if you write few lines to wipe out my confusion. thanks

  66. Avatar for jordan
    jordan March 8th, 2015

    LOL!! Great post!

    I'd like to add the old DP (Data Drocessing) Law of System Delivery -

    "Double your estimate and replace with next unit of time". For example: original estimate: 6 weeks. Double: 12 weeks. Next unit of time: 12months.

    This law still works all the time in Corporate IT!

  67. Avatar for Marty
    Marty April 8th, 2015

    You shouldn't pass data over the wire that shouldn't be viewed by the client. A simple packet sniffer will pick this up in second.

  68. Avatar for haacked
    haacked April 8th, 2015

    Yeah, but with this specific attack, the attacker isn't between the client and the server. So a packet sniffer won't pick up the data. The JSON hijacking is what gets the data over to the attacker.

  69. Avatar for Daniel Vieira Costa
    Daniel Vieira Costa May 5th, 2015

    Hi Phil! I've been using DefaultAuthenticationTypes.ApplicationCookie (ClaimsIdentity) to sign in my website. In the past, I used to use Session, but we knows the problem handling it. Do you think that using authentication with cookies, could be a problem and put my website in risk when using JSON?

    Best Regards,

  70. Avatar for haacked
    haacked May 5th, 2015

    Well sessions are implemented using cookies. So as long as you properly secure the cookies in the same way sessions do, you'll be OK. But you have to be very careful with this. I'd look for existing methods in the framework for doing this, setting expirations on the tokens inside of cookies, etc.

  71. Avatar for Behi
    Behi July 6th, 2015

    This was a great read, but in short this looks like the CSRF attack and other, and IMHO, better solutions are available for it: https://en.m.wikipedia.org/....

    Using POST for GETTING data is against REST principles.

    Rails provides a very easy way to protect against these attacks. I am new to .NET, but I prefer declaring that a controller or action requires CSRF protection rather than making it respond to POST requests.

  72. Avatar for Frank
    Frank June 16th, 2016

    Hi, I read an article on Stack Overflow about this issue, however accepted answer on that page claims that this issue is not applicable to later version of browsers. So, have tested this on current version of browsers or basically, is this still current vulnerability for current browsers? Thanks in advance

  73. Avatar for Dima
    Dima August 11th, 2016

    The root problem is cookie highjacking here and for this - rule of a thumb that all request producing data must have auth token on request header.

  74. Avatar for Dani_S
    Dani_S August 21st, 2017

    Am I the only one who doesn't get this?

    "If by blind bad luck you’re still logged into the original site when you
    click through to the link, the browser will send your authentication
    cookie to the website when it loads the script referenced in the script

    How does a cookie originated from site A goes to site B? I thought this was impossible, because of the very way cookies work, in that they only go back and forth between the server who created it and the client site for which it was meant to be created.


  75. Avatar for haacked
    haacked August 21st, 2017

    The cookie from Site A never goes to Site B. The issue here is that Site B (the bad site) is using a SCRIPT tag to load a script from Site A. That's allowed because the authentication cookie for A still goes to A.

    The bad part is this: if you try to load a JSON endpoint with a script tag, it would normally fail either because most JSON endpoints only respond to a POST request or they return a JSON object which isn't a valid JavaScript file. But in the circumstance where you're loading a JSON endpoint that responds to a GET request and the response is an array, a JSON array is also a valid script. And due to old browser bugs, you can hook the array constructor and execute code.

    This particular issue has long been fixed in all modern browsers. However, it's possible it could regress due to future new features or bad browser plugins.

  76. Avatar for Ashish
    Ashish March 21st, 2018

    I too agree with you that Making POST to every request returning the JSON is not best way to handle same. A solution I taught of that we can also validate on request referrer and do not server to requests from other domain

  77. Avatar for haacked
    haacked March 21st, 2018

    The request referrer can be spoofed. It is NOT secure to rely on it.

  78. Avatar for Ashish
    Ashish April 24th, 2018

    Hi, it is also possible for an attacker to make the jquery post request to the vulnerable site, then also attacker can get the data. How HTTP post will prevent it?
    I thought of making request POST and also pass the Anti forgery token with the POST request which returning JOSN, then will it work?
    Referring the stack overflow link https://stackoverflow.com/q...