CSRF protection and Single Page Apps

Well here is how I ended up implementing CSRF:

On the first request, sets a CSRF token as a cookie. Every subsequent AJAX requests include the CSRF token as a X-CSRF-Token HTTP header.

Django has some nice documentation on how to do this cleanly with jQuery: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

Edit: An alternative approach whitelists requests that contain the X-Requested-With header. It seems that's what Rails does. But as @damio pointed out below, the X-Requested-With is a security hazard, Django and Rails reverted back to not using it and forcing a token.


You're in luck! Just about 2 weeks ago I was asked the same question, and after a bit of head-scratching, I came up with the following. Please keep in mind that this is not well peer-reviewed, so we'll see how the comments and voting goes. Personally, I think it's a good technique.

1. First request

Once you receive the first request to load your application, generate a secure random identifier and store it in a session variable on the server, then send it to the client. I'd embed it in the page just before </body>.

<script>setToken('<% print SESSION[TOKEN] %>');</script>
</body>

Your setToken() would assign the token value to the variable in which you'd keep the token.

2. Subsequent requests

With each request you'd add that token to the list of parameters, like token=TOKEN, and the serve would check it against the one stored in the session variable.

3. Refreshing the token

It's not really mandatory, but it's a good idea to refresh the token every once in a while, say 15 minutes. When you get a request after the token expires (you have the expiry time in the session variable), you respond to it normally (act optimistically) but in the response you tell the client that the old token has expired and it should start using the new one.

The client reacts to that by telling the server that it now knows the new token, once the server gets that request it starts using the new token and responds to the client with an OK message, once client receives 200 OK it means that they're both in sync and the client starts using the new token.

Note: A key element in the process is HTTPS usage. You don't want a Man in the Middle to sniff the token. But then again, an MitM would be able to sniff the cookies and hijack the session anyway.