Why make an extremely complicated set up, with many edge cases, all to save yourself from a single token?
- Privacy extensions often times block referrer headers.
- POST requests are usually necessary.
- Open redirects are common bugs, and getting your website to initiate one can be a problem.
- Disabling CORS also relies on you killing crossdomain.xml, which you might overlook.
Instead you can just roll out CSRF tokens.
Having rolled them out myself many times. You probably want to use a library if you aren't a cryptographer or security person:
I've seen other people mention SameSite cookies, but we aren't near a time when browsers all support them. Don't get fancy preventing CSRF. It's a stupid bug.
Not to be That Guy, but: your sample will reuse the same token over and over until it expires, which is how you get the BREACH attack.
In Django 1.10, we switched the CSRF token generation to use a consistent base value, but to combine it in a reversible way with a randomly-generated per-request nonce. CSRF verification then consists of recovering the base value and checking it; this lets you have a longer-lived "token" without sending the same value in every request/response cycle.
Not to be That Guy 2.0; but doesn't all of this ad hoc hackery (CSRF tokens included, IMHO) around request authorisation and, if you'll permit me to extend the discussion a bit, also around request rate limiting, indicate that there might be something terribly broken at the heart of web requests?
In a same way that I feel the proliferation of front end frameworks indicates something is terribly broken at a cellular level about UI in HTML.
Might it not be time for a radical rethink? Can we not hope for a piercing, elegant solution?
You're wrong. If this is generated every time the page loads you get a new token each time. OR you have to transmit a god awful amount of data on the same page.
When I work for a company that accepts GBs of data over the same TLS connection on a single page, I'll worry about breach and only generating a CSRF token every time a page loads.
From the sample code provided I was assuming the value would not update on every request (since, if you were changing the expiration timestamp on every request you'd have a bit more work to do than you've shown here -- and either way the sample you've provided isn't a great way to generate the token).
I've generated this exact token at several companies and it's worked great.
An expiration of one day is not 86400 it's unix_time()+86400, to clarify. It's not stored in the users session and is completely stateless. It's great!
It has every property a csrf token needs
- per user
- not guessable or forgeable
- expires
Since it is stateless it doesn't require db lookups which can be an additional benefit. If you complain that it lacks the ability to be revoked I challenge you to find a single instance of people revoking csrf tokens.
Agreed. The solution being proposed with CORS is fragile and complex. Maybe it will be viable in another 5 years' time, with better browser support. But I can't imagine that after reading the article, any dev in his/her right mind will be rushing off to ditch CSRF tokens on production sites.
CSRF tokens are taken care of by every web framework out there, anyway. They really should involve zero work to implement. For example, Flask-WTF handles them virtually transparently.
I would like to note that not all frameworks are viable at-scale. We ran into that with Meteor, as it scaled extremely poorly. It didn't implement CSRF tokens, but also didn't use cookies to store auth data, so it didn't much matter.
We only target recent versions of modern browsers, as a consequence of our user base, so we're more able to move to an origin-based solution.
I believe the point of the article is that tokens don't get sent for HEAD or OPTIONS requests, and it's very possible that your API/server are still performing some sort of action on such requests. Or even if not performing a specific action, it still needs to be dealt with and hence is a DDOS vector.
In addition to everything you've mentioned, the double submit cookie approach for csrf defense saves you from storing any state if you don't want to use a backend session.
Having rolled them out myself many times. You probably want to use a library if you aren't a cryptographer or security person:
I've seen other people mention SameSite cookies, but we aren't near a time when browsers all support them. Don't get fancy preventing CSRF. It's a stupid bug.