JSON and Browser Security

By Douglas CrockfordApril 10th, 2007

JSON is a data interchange format. It is used in the transmission of data between machines. Since it carries only data, it is security-neutral. The security of systems that use JSON is determined by the quality of the design of those systems. JSON itself introduces no vulnerabilities.

The web browser is a peculiar application environment. The security model of the browser was forged through a long series of foreseeable and painful blunders. Most of the holes in the browser have been plugged, but in some cases the plugs become annoyances which must be circumvented, and that circumvention leads, foreseeably and ever-painfully, to a continuing series of blunders.

This pain can be avoided by adopting good practices. Often, so-called experts seem to be incapable of distinguishing the good practices from the bad ones, so there is a lot of bad advice available on the web.

I will share here a small set of principles which can be seen to be true. If you hold to these principles, you will be much less likely to adopt bad practices.

Never Trust The Browser

The browser cannot and will not protect your secrets, so never send it your secret sauce. Keep your critical processes on the server. If you are doing input validation in the browser, it is for the user’s convenience. Everything that the browser sends to the server must be validated.

Keep Data Clean

JSON is a subset of JavaScript, which makes it especially easy to use in web applications. The eval function can take a text from XMLHttpRequest and instantly inflate it into a useful data structure. Be aware however that the eval function is extremely unsafe. If there is the slightest chance that the server is not encoding the JSON correctly, then use the parseJSON method instead. The parseJSON method uses a regular expression to ensure that there is nothing dangerous in the text. The next edition of JavaScript will have parseJSON built in. For now, you can get parseJSON at http://www.JSON.org/json.js.

On the server side, always use good JSON encoders and decoders.

Script Tags

Script tags are exempt from the Same Origin Policy. That means that any script from any site can potentially be loaded into any page. There are some very important consequences of this.

Any page that includes scripts from other sites is not secure. External scripts can be used to deliver ads or search result options, or logging, or alerts, or buddy lists, or lots of other nice things. Unfortunately, the designs of JavaScript and the DOM did not anticipate such useful services, so they offer absolutely no security around them. Every script on the page has access to everything on the page. When you load a script on a page, you are authorizing that script to have access to all of your confidential information and all of your user’s confidential information. You are also authorizing that script to access your server on the user’s behalf to do anything it wants. It is not possible to distinguish between requests made by the user and requests made by an invited script. Hopefully, some day soon, browsers will offer some degree of modularity that would limit the danger. Until then, script tags are extremely dangerous.

Another use of script tags is to deliver JSON data from different sites. There is absolutely no protection against the case where the different site sends dangerous scripts instead of benign JSON data. Hopefully, some day soon, browsers will offer safe cross-site data transport. Script tags are too dangerous to use for data transport.

Script tags can also be used to deliver Ajax Libraries. Do not load libraries from other sites unless you have a high level of trust in the vendors.

Don’t Send Data To Strangers

If your server sends sensitive data to an evil web page, there is a good chance that the browser will deliver it. In some cases the Same Origin Policy is supposed to block such deliveries, but the fact is that browsers are buggy and sometimes the data will go through. It doesn’t make sense to get mad at the browser. The secure release of confidential information is the server’s responsibility. That responsibility should never be delegated to the browser.

All requests must be authenticated. You must have some secret which is known only by the page that indicates that it should be given the goods. Cookies are not adequate authentication. Don’t use a cookie as the secret. JSON often works best in a dialog: POST a request including the secret in the JSON payload, and get a JSON response in return along with a new secret.

Since script tags are exempt from the Same Origin Policy, a script tag can be used from any page to make a GET request of your server. The request will even include your cookies. If the response contains confidential information, then your server must refuse the request.

There are people who are selling magic wrappers to put around JSON text to prevent delivery to unauthorized receivers. Avoid that stuff. It will fail when new browser bugs are created and discovered, and in some cases might introduce painful new exploits.

Use SSL

Any time you are transmitting confidential information or requests for confidential information, use SSL. It provides link encryption so that your secrets are not revealed in transit.

29 Comments

  1. Could you elaborate more about this…. Exactly how you would suggest this to be done. How did the page get the secret to begin with and how does it store it so a different script can’t get a hold of it? Thanks.

    All requests must be authenticated. You must have some secret which is
    known only by the page that indicates that it should be given the goods.
    Cookies are not adequate authentication. Don’t use a cookie as the secret.
    JSON often works best in a dialog: POST a request including
    the secret in the JSON payload, and get a JSON response in return along
    with a new secret.

  2. [...] JSON и безопастность JSON is a data interchange format. It is used in the transmission of data between machines. Since it carries only data, it is security-neutral. The security of systems that use JSON is determined by the quality of the design of those systems. JSON itself introduces no vulnerabilities. [...]

  3. TC, The secret must come from the server and can be embedded in the HTML. It is not possible to hide the secret from scripts on the page. Every script has access to everything. That is why pages with external scripts are not secure.

  4. Seems like we can’t use a nonce (one-time-use key) as the secret, ’cause we will be making an arbitrary number of asynchronous calls.

    So, a session-long secret would have to be used.

    The secret would ideally be kept as a cookie — embedding it in Javascript leads to potential String.prototype redefinition attacks, and embedding it in HTML potentially makes it vulnerable to session fixation attacks (which could allow an attacker to retrieve the key.)

  5. Patrick Hunlock said:
    April 10, 2007 at 6:03 pm

    A very interesting and enlightening read — thank you. I would suggest that what Javascript needs — really more than anything — is a getJSON(url) method. There is absolutely no reason in the world not to have this. If the method gets the url and tries to parse it as JSON and it is JSON then its easy to pass to the script, if it’s not, its easy enough to throw an error.

    Because the method would allow only JSON data it could be exempt from the browser’s same-domain restrictions because it wouldn’t allow scraping and other nasty things the same-domain restrictions were created to guard against. getXML wouldn’t protect in the same way because, well web-pages are XML.

    If you want to revolutionize the web, again, then a same-domain exempt getJSON method simply has to be a part of Javascript’s future. IMHO of course.

  6. [...] JSON and Browser Security » Yahoo! User Interface Blog (tags: json javascript security webdev) [...]

  7. Weird ie 6 bug in the layout of this blog post. The first paragraph under the heading “Keep Data Clean” is cut off.

    The parseJSON method uses a regular expression to ensure th

    On the server side, always use good JSON encoders and decoders.

    Interestingly, when I cut and paste this section, all of the text is pasted.

    I have refreshed a number of times. The source looks okay.

    Thought you might like to know.

  8. JSON and Browser Security on the YUI Blog…

    Douglas Crockford posts a set of guidelines on writing secure web applications using remote scripting and JSON on the YUI Blog.
    JSON is a data interchange format. It is used in the transmission of data between machines. Since it carries only data, it …

  9. In all of the current hysteria that seems to be building momentum, it’s nice to read some of the facts put down in a structured logical format. I’ll be using this page as a reference tool for a while I fear. Excellent post. Big Thumbs Up.

  10. @ Tim McCormack

    I don’t see why you can’t use a nonce. Client server interactions are like good conversations, one side says something and the other responds. You shouldn’t ever but in a position where the client is punting requests at the server and not then expect a response.

    To use a nonce, just have your server fire back a new nonce as part of the response. That way you have a stepping stone approach.

    - Arrive at a page
    - Get a key
    - Request and send key (XHR or traditional)
    - Authenticate key, send response with new key
    - Request and send new key
    - Authenticate and…..
    - repeat to fade

    There are even degrees of half-life you could build in, like the S3 approach where the key is time based (partially). That way you could give each key a lifetime, if you try to use it after that lifetime expires you get a “session expired” style response. In fact the more I think about it, the more like a non cookie based rolling session variable it seems.

  11. [...] I was just perusing Douglas Crockfords post from yesterday, it’s a calming voice of reason in the current JSON and AJAX is s security vulnerability witch hunt that seems to be this quarters tech blog writers topic of choice. [...]

  12. [...] JSON and Browser Security » Yahoo! User Interface Blog (tags: ajax blog client browser dhtml hack interesting javascript toread yui webdev security json **) [...]

  13. Securing apps that use JSON…

    Douglas Crockford (wikidpedia) wrote a blog post on the Yahoo! User Interface Blog about securing web applications that use JSON.  The insecurity of JSON has been a hot topic on numerous blogs (here, here and here). In Douglas’ blog post he….

  14. Excellent article, i agree at 100%, in these days i’m studying a page to show that poisoning the json data is not useful. Regards ;)

  15. We were very happy to see Doug’s mention of the serving to people you don’t know but the client side approach just isn’t right but at least we are finally on the right track to addressing the exploit. Roughly a month back we were following the discussion about security with JSON and others at Ajaxian and came to determine that it is our belief there is no solid direct solution on the client side. The main concern has to do with misappropriation of the script to do some CSRF attack and this is not easily solvable client side since your secrets are exposed in code and transmission. A server-side solution similar to that employed with anti-image leeching appears to do the trick. We encourage readers to look at this article http://www.port80software.com/.com/200ok/archive/2007/03/15
    which it explains it. We’ve tried to get Dion to post this at Ajaxian but to no avail, forget the product mention and open the brain it is the solution as far as we can tell and can be accomplished in many ways.

  16. [...] JSON and Browser Security » Yahoo! User Interface Blog Good summary from Crockford on JSON and browser security issues. (tags: json ajax crockford) [...]

  17. [...] JSON and Browser Security Never Trust The Browser, Keep Data Clean, Script Tags, Don’t Send Data To Strangers, Use SSL – The secret must come from the server and can be embedded in the HTML. I would suggest that what Javascript needs more than anything is a getJSON(url) method. (tags: JSON Security Browsers Data SSL) [...]

  18. jp, the reason you can’t do a “rolling nonce” (to coin a phrase) is that we’re dealing with asynchronous requests. You aren’t guaranteed a response (with new key) to occur before the next request.

    Additionally, we should consider the spectre of multiple tabs or windows. New authentication keys must be shared between open views. (Cookie-based storage of authentication keys?)

  19. Tim, yup totally agree (the link above goes to my blog post about it), the nonce really is an excessive level of paranoia, which is probably only worthwhile for very specific applications (Amazon’s S3 as an example – and they don’t even do real server generated Nonce’s…but anyway). Some sort of per session key is probably enough for all applications.

  20. Tom Metro said:
    May 2, 2007 at 7:09 pm

    The correct URL for the article mentioned in a comment above is:
    http://www.port80software.com/200ok/archive/2007/03/15/29258.aspx

    It basically says to incorporate rules on the server side to validate the referrer header as part of the authorization process.

    However, I think this approach is equally vulnerable to an attack that exploits XSS to inject a rogue SCRIPT tag into the target application’s HTML. The rogue JavaScript will run in the application’s context, have access to its secretes, and requests it makes to your server (if well engineered) will be indistinguishable from legitimate requests.

    -Tom

  21. [...] April 10, 2007 at 10:14 am by Douglas Crockford 翻译:Frank Cheung 文章出处:http://yuiblog.com/blog/2007/04/10/json-and-browser-security [...]

  22. [...] JSON and Browser Security » Yahoo! User Interface Blog JSON is a data interchange format. It is used in the transmission of data between machines. Since it carries only data, it is security-neutral. The security of systems that use JSON is determined by the quality of the design of those systems. JSON itself [...]

  23. I’ve some issues with JSON string.
    can anyone tell me the reason for not allowing # and ;.

    In my application I’ve have escape utility, which escapes all special character to a standard ECMA character. Which will be like “&#”+charCode+”;”

    This works in all cases like string to XML, string to HTML and XML to html.

    when i try to use JSON as my data interchange format, it is not tokenizing my string which has got ECMA characters.

    Thanks,
    Sivaraj.

  24. Douglas,
    Great article. Everything is well explained, except I am still confused by the section “Don’t Send Data to Strangers” and your previous answer to TC.

    Why am I confused?

    1. So external scripts are dangerous, we hear that. But even if I do not include any external script, this still remains as a valid concern, right? Because someone evil do NOT really need me to include their evil scripts in order to steal information, they can just make the requests directly to my server? Without any form of authentication, my server cannot tell whether the request come from my page or anywhere else, and it’s bad if my server blindly return the JSON data to anyone, right?

    2. If I understand correctly, the your proposed solution is something like this:

    a. Have the server code authenticate the very first request. Assume valid credential, then create a secret and return along in the JSON payload.

    b. In subsequent requests, have the server code authenticate using the secrets from previous responses and keep generate new secrets to send back in each response?

    Thanks for clarifying.

  25. [...] it, so that the developer doesn’t have to use eval. And last April, Doug Crockford argued in a piece on JSON and browser security that JSON is security neutral (as near as I can make out, because the security problem is in the [...]

  26. So it would do no good to store the key in a closure?

  27. Closures are safe, but there is not a secure way to get the key into the closure. So no good.

  28. Hi, In My application i have used JSON to fetch data from server on selection of item from dropdown list.

    Its working fine on local machine but when i am trying to access this page remotely it give me error like

    “This page is accessing information that is not under its control. This poses a security risk. Do you want to continue”

    Can anybody suggest me what all things i need to do to avoid such kind of error.

  29. There’re few things more than SSL to secure the secret.

    We could use a server-generated script to get the secret and use a funtion similar to this:

    sha1( “SALT” + IP + SESSION_ID + SESSION["RAND_GENERATED_KEY"] )

    and validate it each time.

    This way, to steal the session anyone should use at least the same IP, but also the same browser and shold have passed relatively short time to prevent server session wipening.