No more CSRF hassles: Safe Requests in TYPO3 Flow 2.0

We are approaching the finishing line for TYPO3 Flow 2.0 - the feature set is frozen now, apart from one important addition which is currently in the works: support for "safe request methods" and removing CSRF tokens from URIs. We didn't plan for this and it comes at pretty short notice before the Inspiring Flow conference. But it's doable, if we can quickly raise some funds for two days of development. If you ever cursed about CSRF tokens in your links ... read on.

Since its first version Flow comes with built-in protection against Cross-Site Request Forgery attacks: an attacker prepares a link which does something harmful - for example deleting a customer record - and sends it to a user who unintentionally clicks the link while being logged in. TYPOFlow protects links to method calls which are protected by a policy by requiring a CSRF token to be sent along with the request. This token is bound to an active user session which means that if you want to execute a CSRF attack you additionally need to know the user's session id and a server-side secret or get ahold of a "hot" link.

Buckle up – it's only safe when you use it

Consider a deleteAction() in one of your action controllers which is protected by a security policy. When you let Flow generate links to this action in your Fluid templates, a CSRF token is appended, which results in links like these (please don't click it, it would delete all my blog posts):

Now, if you click such a link without a matching, active user session, Flow's security framework will block the request. That's great ... unless you want to send such a link to your colleague or post it on Unfortunately, Flow cannot know in advance what you are going to do with the link: will you only use it for a read-only action or is it really a link which is potentially harmful?

Having CSRF tokens in your URIs is a hassle. That's why the @SkipCSRF feature has become wildly used in many Flow projects. Bummer.

If it's safe, you can consider it safe

If Flow knew which request can be considered safe (that is: it might show sensitive data - which is no problem, because the logged in user would see it - but doesn't change or destroy any data) it could skip checking for a CSRF token right away. Fortunately there is a definition for "safe" requests, in our favorite spec, RFC 2616:

In particular, the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". This allows user agents to represent other methods, such as POST, PUT and DELETE, in a special way, so that the user is made aware of the fact that a possibly unsafe action is being requested.

If we support (and partially enforce) this paradigm in Flow (which we will), we can assume that a GET request is not vulnerable to CSRF attacks and thus don't have to generate CSRF tokens for these requests. In fact we will never have to add a CSRF token to a URI ever again because:

  • GET requests are "safe"
  • POST, PUT, ... requests can submit a CSRF token in their message body, submitted via a hidden field in a form or similar
  • DELETE, ... requests can submit a CSRF token through a special message header

Implementing safe and frustration-free requests

TYPO3 Flow 2.0 will support the notion of safe request methods in these ways:

  1. CSRF tokens won't be checked for "safe" requests
  2. CSRF tokens still are required for "non-safe" request methods to methods protected by a policy
  3. the persistence layer will not persist any changes (with persistAll()) for GET requests
  4. the link view helpers and UriBuilder won't add any CSRF tokens anymore
  5. the form view helper will add a token to their set of hidden fields

Making it happen

I already implemented a proof of concept for safe requests, but in order to get rid of the whole aspect which renders tokens into URIs, there's a lot more work necessary. I'm way out of funds for doing this on my own currently (which is a longer story for a night at the bar), so in order to make this happen we need to crowd fund the feature.

Here's the deal: if we can raise 600 - 800 € (more always possible), I can implement this feature in time for the conference end of this week. Just leave your offer in the comments and I'll get back to you. And if you can spend some more: the Flow team urgently needs funding for some more hours of code reviews and release management - any help appreciated.

Leave a reply