Making CSRF tokens (transient keys) easier to work with
I've lately been thinking about the CSRF tokens and how they could be made easier to work with. This came up when I was trying to test some authentication endpoints that require a CSRF token, but don't require an authenticated user. It was a pain to test in ARC because the endpoints required CSRF protection but I generating a token is something that the API doesn't do.
Here are a couple of ideas:
Make the CSRF cookie readable by document.cookie
Removing the HTTP-only flag from the CSRF cookie would allow the document to read it and submit directly from the cookie. This has a few benefits:
- We don't have to put the CSRF token in the page anywhere.
- We can refresh the token without having to do any special processing.
- AJAX libraries like Axios have built in support for this method. This is actually where I got the idea.
Relax the CSRF requirements for tokens submitted through the header.
A while back I read that you don't actually need a random stored CSRF token if you just look for the existence of some custom header that is agreed upon. This would allow clients to set the header with whatever value they want. This is by far the easiest method to work with, however we'd still need a token for non AJAX requests.
Potential Drawbacks
Although these methods are pretty straightforward, the drawback for both of them is the uncertainty that they don't present their own security issues. That's the main reason why I'm bringing this up here.
I do want to explore these solutions though. If we are able to simplify CSRF protection we can also work towards making CSRF a core part of Vanilla and we won't have to opt in to the checks in every controller method. The APIv2 already does this.
Comments
-
This HackerOne report is relevant to the custom header: https://hackerone.com/reports/44146.
Some highlights:
The only thing protecting this resource from CSRF attacks is the demand that the "X-Requested-With: XMLHttpRequest" request header is present on the call.
At first sight, this seems impossible to circumvent because sending AJAX requests cross-domain is blocked by CORS, but there is a way to spoof the "X-Requested-With" request header in Flash.
and
It's possible to send the "X-Requested-With" header with Flash, but we can't send it cross-domain due to the SOP implementation with Adobe's crossdomain.xml files. However, we can trick Flash into sending the request anyway by issuing the request to a domain that does allow it, which in turn sends a HTTP 307 redirect to the resource that we want to target. Flash will send the request to the new resource before requesting crossdomain.xml on the new domain.
Additionally:
http://resources.infosecinstitute.com/bypassing-csrf-protections-fun-profit/
It seems to be patched in modern browsers? https://www.computerworld.com/article/2506355/security0/update--firefox-update-will-patch-csrf-bug--mozilla-says.html but the the vimeo report seems to be more recent.
0 -
That looks like an issue with Vimeo's Flash-based player and wouldn't affect HTML pages. We do have a flash file used with easyXDM, but I don't see a crossdomain.xml file.
0 -
Another pro to a transient-key-less custom header. We don't have to generate a key for stuff like authentication which would git rid of invalid CSRF tokens.
0 -
Okay I've taken the plunge and relaxed the CSRF checks for AJAX requests. I think my reading of the article prevents the bypass you mentioned @charrondev.
0