This spawned some great hallway conversations and got me really thinking about how we solve CSRF issues today. I kept coming back to an application I was working on recently that uses GWT and how I had to solve CSRF for that particular situation. See, normally the solution is to append a parameter on to the GET or POST request with a unique token that the server can verify against. Depending on who you talk to - sometimes this token has a lifespan of a session, and sometimes it is only a single request. Some would argue that for more sensitive applications you should use a per-request token and per-session tokens could be used in other places.
Google has posted an article all about securing GWT Applications - while I normally commend google on their suggestions as they pertain to security in software, I could not believe what they were suggesting as a solution to CSRF. The full article can be read here - but here is an excerpt outlining the proposed solution.
First thought that popped into my mind when I read that (and maybe you had the same thought) was that the proposed solution of duplicating a session cookie doesn't solve the problem at all. I suppose this could be the case in a Framejacking CSRF Exploit, that this would solve that issue - but if I send a crafted link to a handful of users to their bank to transfer 1 million dollars to my account like:
"Dear Sir or Madam, I am writing you from EvilHacker Bank and Trust to let you know about a new policy regarding our interest rates - please click the evil link below to get pwned.
EvilHacker Bank and Trust"How does a cookie protect the user who is possibly already authenticated to the EvilHacker Bank application with a session cookie in their browser (and said duplicate session cookie). The browser is going to send both cookies because it does in fact, have access to them.
Well, that's completely unacceptable, I thought to myself. That doesn't protect the application or users of the application at all from CSRF. So I set out to come up with my own solution.
- App Server needs a filter or some means to setup the session on the first request made to the application. This is standard CSRF protection behavior.
- Created a filter (CSRFFilter) to generate a CSRF nonce when the session is created and set that as a cookie that gets sent back to the client.
- Client application reads the nonce from the cookie and alters the request to add a custom header containing the nonce.
- Server checks for either the presence of a request parameter or request header containing the CSRF nonce and verifies it against the value stored on the session (not in the cookie)
- A new nonce is generated every time a new session is created.
So what does this really mean?
It means that since SOP rules won't allow a Java Applet (post 1.6 update 8) or Flash App (unless it is setup completely incorrectly) to make a cross-domain request - you are safe from the attack embedded in a flash or java applet, and since an e-mail client can neither predict the nonce, nor can it send request headers - you are safe from CSRF.
It also means that you cannot have entry-point actions in your application. So if your model is to allow people to accomplish some action by clicking a link from their e-mail - you will want to exclude that service from this solution (or just about any other CSRF protection - here you have are probably going to have to resort to a hash that can be calculated as your CSRF nonce, which still provides ample protection against most threat agents and situations, but is slightly less evil-hacker-proof then using something completely random)
Now on to the argument about sensitive data and the per-request token model. I think this is severely overcomplicating an otherwise simple and elegant solution. A distributed phishing style CSRF attack would have to not only count on a pre-authenticated session but would also have to predict the nonce (which is tied to the authenticated session) which while not completely impossible is so improbable that it equalizes the threat completely. In other words, with this solution - you may have a single successful attack inside millions of years (depending on the width and PRNG used to create the nonce)
The complexity introduced in managing a per-request model in an Ajax application becomes a nightmare full of bugs.
So, in summary - I contest that the per-request model of CSRF nonces is overcomplicated and a complete overkill in 99.9% of cases (there may be the small edge-case where this makes sense).
Remember, the more complicated a Security Control is - the more likely there is a bug in the control that can be exploited to circumvent it.