CSRF: how about setting a header?

A misread blog comment leads to the idea of using a custom request header as a CSRF defence.

I was just reading a post over at Ajaxian and one of the comments from “Nathar Leichoz” caught my eye - I actually misread it at first.

The comment has this code as a potential “solution” to CSRF attacks:

$headers = getallheaders();
if( isset($headers['X-Requested-With']) &&
    $headers['X-Requested-With'] == 'XmlHttpRequest') {
    //...
}

Now that got me thinking. If you’re worried about some accessing your same domain policy). By getting a logged in user of good.com to hit that page, you can trick good.com to authenticate the cookie that user has, and pass the JSON to evil.com’s JavaScript to do with what it wishes.

Now taking aside that fact that currently well structured Object JSON {//stuff} can’t be accessed via a script tag (although many have tried) - See example 5 in my other post.

Lets assume that data structure is not a good sense of security for us (which it really shouldn’t be). What we need is a way to authenticate that that person is who their cookie says they are and that they are on our site, not on evil.com.

Many have suggested checking the headers that get sent through with a request to see if the request is coming from the same domain (almost like a secondary server side version of the ‘Same Domain Policy”). This always seemed like a great idea to me. However it fails because many Browsers might not send those headers and if you ban everyone from getting at your JSON who doesn’t confirm they come from good.com you could block a lot of potential users from your system. That’s not ideal.

The above post made me think, if we’re not able to rely on browsers sending that information, why don’t we just set it ourselves when we do the XHR calls on good.com.

As far as I can see you can’t set headers using a script tag so there would be no way for evil.com to set the header that declares the request is coming from good.com. On good.com when we make the XHR request, we can set that header and be save in the knowledge that it is set and that it is coming from good.com.

But lets be really paranoid for a minute. Lets say that evil.com with it’s infinite knowledge and unlimited resources (a good assumption in security) works out how to set those headers, they could just start setting the Request-URI and pretend to be good.com and we’re vulnerable again.

So that got me thinking, why not set the session information for that user in a unqiue custom header, that way each user has a header value that identifies they are who they say they are, and that they are coming from a good.com page. That combined with traditional cookie authentication, Post only access, and Object structure JSON gives us 3 levels of security that are in different parts of the system (reliance on 1 area for security means your vulnerable if evil.com can hack that area as a whole.

I’d need to test it before I’d be happy to back it in a production environment, but it seemed like a nice idea and one that was worth sharing.

An initial idea of the sort of code you’d run on good.com that the server would then need to validate before responding would be (this example uses the Dojo IO methods):

function sendXHR(requestObj){

  dojo.io.bind({

    url: requestObj.url,

    headers: {
      "DoubleCheck" : dojo.io.cookie.get('sessionCookieMaybe'),
      "thisWindowLocation" : window.location.href
    },

    mimetype: "text/json",

    load: function(type, html, http) {

      handleHtmlResponse(html);

    }
  });
}

First published on jpsykes.com.