JSON is not as safe as people think it is
incompleteness.me
incompleteness.me
AFAIK, the ability to override the Array constructor has been fixed in all modern browsers.
Here's a blog post by John Resig about the same issue: http://ejohn.org/blog/re-securing-json/ (also from 2007).
Is this true? I was able to do it in both Chrome and FF.
Let's say I have a data API http://bank/sensitiveData which returns JSON:
["bmjs", "sensitive", "data"]
.. if your browser has a valid session. Now, if an attacker lures you onto his http://malicioussite, he may try to do: ajax.get("http://bank/sensitiveData).then(sendReceivedDataToMaliciousDatabase)
This will throw an exception, because the browser doesn't allow the cross domain requests to http://bank .However, he _can_ insert a <script> tag that loads it (this is how JSONP works):
<script src="http://bank/sensitiveData"></script>
This will load your sensitive data (assuming you have a session open). If, before this, the attacker has overridden the Array constructor in his site's Javascript, whatever code he has in that constructor will receive your sensitive data (and may send it to his malicious database).Now, if my bank data API actually served your sensitive data as executable Javascript, that is:
var bmjsSensitiveData = new Array("bmjs", "sensitive", "data");
Then you need to cancel your account and find a new bank immediately :) This would be loadable with the <script> tag on a malicious site as shown earlier, and subsequently make the variable bmjsSensitiveData available to the attacker's Javascript (overriding the Array constructor wouldn't even be necessary).Please, please, no. This is terrible advice - do not rely on security by obscurity! This is not even obscure - anybody can open the network monitor in Chrome and get the URL. You should be doing exactly the opposite - publish your URLs and get researchers to investigate them. Give a bounty if they break it and you'll have tons of researchers all happily fixing your security for you! Do not obscure this stuff.
You could also accomplish this by encapsulating things in an object literal (as suggested on the page); requiring POST or a header or returning a non-JS Content-Type; loading an HTML page on the site and using window.postMessage to send the data only to trusted sites; and maybe more ways as well.
http://myapp.com/me/contacts.json
You'd have http://myapp.com/contacts/8df02390908dsf
Where '8df02390908dsf' could be a hash computed from the user's data, but a simple unique ID would suffice - as long as it's stored in document.cookie/localStorage where the third-party website can't access it.The advice is still bad. Rather make your URL as open as possible and actually secure it for an attacker who happens to know it. If a user gets hacked and your response is 'well, nobody should have known the users ID!' then you're going to be looking pretty dumb.
This statement is strictly true: JSON is unsafe for
anything but public data unless you are using
unpredictable URLs. It is true for all data formats.
There was never a good reason to believe that JSON
reduced the need for vigilant design.Your session based generated HTML (i.e. Your Credit Card usage history) is safe against these kind of attacks, also guess what your XML is safe as well and all other data formats that cannot be called and interpreted by JavaScript from another domain. Heck even session based generated images are safe and cannot be read from another domain, other than some rare bugs (they are security bugs and will be fixed, not design issues).
Another format I can think of that cannot keep session based information safe is JavaScript. I wrote about a real world example of this before (a vulnerability in IntenseDebate) : http://www.mavitunasecurity.com/blog/javascript-scope-and-in...
Douglas Crockford defends JSON to the point of making himself look foolish. He causally dismissed this real issue as a non issue, and has done the same with the U+2028/9 line ending issue.
Edit: It is worth pointing out that Google still prefixes their JSON with )]}' to protect users that are still using 2007 browers.
Executing foreign code with eval is bad. Parsing foreign text is not. It was a problem when people misused browsers to conflate them.
Here is how the the attack was performed. On my site, I rewrite the Array constructor. I then add
<script src="http://gmail.com/mycontacts.json"></script>
Now you visit my site, and I now have stolen all your Google contacts, which are protected by your google password.You see this has nothing to do with "eval".
This is about loading 3rd party JSON APIs on the attacker's site using other ways of bypassing SOP.
The first vulnerability (CSRF) isn't specific to JSON APIs, but the second one is.
This was probably more of a concern in 2007. I'm surprised that such an old (and largely irrelevant now) article made the front page.
session_id = '5f5513f8822fdbe5145af33b64d8d970dcf95c6e' ajax_endpoint_secret = 'this is a super secret!'
token = hmac.new( ajax_endpoint_secret, session_id, hashlib.sha1 ).hexdigest()
- or -
token = '3815c118a9e3e663215adba5e0ca626e8bdd5125'
then when your server emits the html page, your AJAX link looks like: https://example.com/ajax_api/3815c118a9e3e663215adba5e0ca626...
Here, we have cryptographically bound the AJAX url to the user's cookies, so the <script> trick won't work any longer as they don't have access to the token.
Second, you can have your server endpoint checking for the 'X-Requested-With: XmlHttpRequest' if you anticipate this to only be accessed via XHR. This is a pretty effective thwart of the <script> attack as well.
Lastly, ensure that your JSON response always is wrapped in curly braces {}. Never respond with [] From my experiments, all browsers interpret this as a code block and breaks processing when <script src=> runs.
if(user is logged in and SSL is on)
emit user.credit_card_transactions as json
You may think everything is okay.Now your user visits my site (With Firefox 2.0), and on my site I have:
<script> // rewrite array contructor </script>
<script src="https://yoursite.com/transactions.json">
Now I have effectively stolen your user's credit card transactions from your site. You see, from your server's point of view, the user is logged in and is connecting over SSL.This is mitigated by modern browsers that don't allow rewriting the array constructor. If you care about users using FF 2.0, then you need XSRF protection. Many frameworks build this in by default.
XSRF can also be used for less nefarious things like: <img src="https://yourserver.com/logout />
For example,
Your app - sends request -> Third party service
Third party service - replies -> JSONp response
Evil website's script on your app -> Hijack/modifies JSONp response -> steals credentials.
Is this possible? In all probability, it should be possible, right?[1]It's a loophole (kind of) for executing Javascript across different domains. http://en.wikipedia.org/wiki/JSONP
CORS safely solves this problem. http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
CORS solves a different problem, in that you don't have to eval 3rd party code. If the remote service provider gets hacked, then your site may not get compromised.
CORS solves it because you can WHITELIST the domains that can access the data, which is huge! Just like crossdomain.xml in Flash and ContenPolicy in Silverlight.
You are right though if the format is still JSON you are still vulnerable to the same attack, however CORS doesn't require you to use any format particularly, so it's possibly to use any other data format.
JSON-text = object / array