JSON security best practices?

Solution 1:

There are a number of security attacks against JSON, especially XSRF.

The vulnerability occurs when a web service uses cookies for authentication, and responds with a JSON array containing sensitive data in response to a GET request.

If an attacker can trick a user who is logged into a service, naive-webapp.com, into visiting their site (or any site that embeds an IFRAME they control, e.g. via embedded ads) then they can insert a <script> tag with a SRC to the naive-webapp.com, and potentially steal the user's data. This depends on a javascript quirk with the JavaScript Array constructor like this:

 <script>
   // Overload the Array constructor so we can intercept data
   var stolenArrays = [];
   var RealArray = Array;
   Array = function () {
     var arr = RealArray.apply(arguments);
     stolenArrays.push(arr);
     return arr;
   }
 </script>
 <!-- even though the attacker can't access the cookies,
   - he can cause the browser to send them to naive-webapp.com -->
 <script src="//naive-webapp.com/..."></script>
 <script>
   // now stolenArrays contains any data from the parsed JSON
 </script>

EcmaScript 5 has fixed the confusing behavior that caused [] to look up Array on the global object and many modern browsers are no longer susceptible to this attack.

Incidentally, Oil is wrong about unpredictable URLs. Cryptographically secure random identifiers in URLs are a fine way to protect resources. Identity based security is not a panacea as Oil suggests. See http://waterken.sourceforge.net/ for an example of a secure distributed application scheme based on cryptographically secure identifiers in URLs that does not require a concept of identity.

EDIT:

When considering JSON vs XML, you should be aware of XML specific attack vectors as well.

XXE, XML External entities attacks, use crafted XML to access file system and network resources through the firewall.

<!DOCTYPE root 
[
<!ENTITY foo SYSTEM "file:///c:/winnt/win.ini">
]>
...
<in>&foo;</in>

The Application embeds the input (parameter "in", which contains the win.ini file) to the web service response.

Solution 2:

The main security hole from the blog (CSRF), is not JSON specific. It's just as big a hole using XML instead. Indeed, it's just as bad with no asynchronous calls at all; regular links are just as vulnerable.

When people talk about unique URLs, they generally DON'T mean http://yourbank.com/json-api/your-name/big-long-key-unique-to-you/statement. Instead, it's more common to make something else about the request unique; namely a value in the FORM post, or a URL parameter.

Usually this involves a random token inserted into the FORM on the server side, and then checked when a request is made.

The array/object thing is news to me:

Script-Tags: The attacker can embed a script tag pointing at a remote server and the browser will effectively eval() the reply for you, however it throws away the response and since JSON is all response, you're safe.

In that case, your site doesn't need to use JSON at all to be vulnerable. But yeah, if an attacker can insert random HTML into your site, you're toast.

Solution 3:

it's still best to protect your secure data with un-predictable URLs.

Emphasis mine. What nonsense! It's best to protect your secure data with some proper authentication and possibly some encryption on top of that. JSON exchanges can still use existing authentication techniques (eg sessions through cookies) and SSL.

Relying on somebody not guessing a URL (what they're effectively talking about) will only be a reasonable technique (and even then, only just) when you're using JSON to export data to an anonymous third party (eg a web service). One example is Google's various web service API where anonymous users access Google-data through other websites. They use domain-referrer and API keys to make sure the man-in-the-middle website is allowed to provide Gooogle data.

If you're just using JSON to send private data to and from a direct, known user agent, use some real authentication and encryption. If you're trying to provide a webservice, then it really depends on how "secure" this data is going to be. If it's just public data and you don't mind who can read it, I don't see the point in making a hashy URL.


Edit: to demonstrate what they mean, consider this. Imagine your bank provided a JSON API for getting statements. If I could just type http://yourbank.com/json-api/your-name/statement, you probably wouldn't be best pleased.

They could generate a unique string for your account that was required in any JSON request though, eg: http://yourbank.com/json-api/your-name/big-long-key-unique-to-you/statement

I would have far less chance of being able to guess that. But would you really want that being the only buffer between your genuinely secure data and potential identity thieves? No.