If your use of CSRF tokens is purely for preventing cross-site request forgery (and not things like form expiry or double-submit protection, which are commonly paired with it, for better or for worse) then CSRF tokens are genuinely obsolete and unnecessary, and you should set your SameSite attribute on your cookies to ensure you’re protected against CSRF in the most browsers (meaning all browsers from at least the last couple of years—including IE11 updated within that time, by the way—rather than probably just Chrome at present).
This isn't true. Although SameSite is a good defence in depth, it provides no protection against CSRF from sub-domains (subdomain hijacking is fairly common), or in older browsers. It also is incompatible with some site features - e.g. OIDC form_post response mode, SAML SLO with HTTP POST binding, etc.
Subdomain hijacking is only possible if you’ve allowed subdomains to be used for such other things, which I strongly assert is rare.
Older browsers: all browser releases from the last couple of years support it (including IE11); browsers from before then should not be being used on the public internet under any circumstances. It should be a negligible fraction of your user base that uses such browsers, and so long as you’re also happy to break IE11, a safe path (from a security perspective) is to actively break the site for old browsers by blacklisting them or checking for support of a comparatively recent feature. (Just don’t do a whitelist by user agent string, that approach is unmitigatably bad.)
You’re correct about some auth systems not playing nicely with strict same-site cookies, because they’ve been designed with certain assumptions in mind. I’m not particularly conversant with that space, never having had to interact with such a system.
Which is one reason why a best practice (and a very common practice, though a long way off universal) is to make sure that the cookies are scoped to your app only, e.g. by putting your app on a subdomain of its own and scoping your auth cookies to that subdomain.
That doesn't impact CSRF at all. If I send a request from a page on foo.example.com to api.example.com your browser will send those cookies no matter how tightly scoped they are because the destination of the request matches the cookie. It will send those cookies whether you use host cookies, add a __Host_ prefix, set SameSite=strict, Secure, HttpOnly, etc, etc, etc.
If you want to protect against these attacks with basic cookie attributes you can use SameSite and register your site (and any intermediate sub-domains) on the public suffix list to effectively shun your subdomains as being completely separate sites.
If you’re going from foo.example.com to api.example.com, sure, SameSite won’t protect you because those two origins are considered same-site. So don’t do that: keep your API calls on foo.example.com, with domain=foo.example.com cookies.
Also, I seem to recall the PSL maintainers requesting at some point that people not do what you describe, because it wouldn’t scale at all.
Firstly, setting the domain attribute on a cookie explicitly allows sub-domains. You want to leave that off to enable host-only cookies. But secondly, as I just said the host/domain on the cookie does nothing at all to prevent cross-origin requests to that domain, which is the relevant concern for CSRF. Setting the domain/host is completely irrelevant to this attack.
Yes, adding to PSL is not at all scalable and will likely cause you a world of pain down the road. It was not intended as a serious suggestion. Use proper CSRF defences.
I've found that a key part of CSRF protection is ensuring it gets added everywhere consistently. When new features need to be done yesterday and you have to review code from 20+ junior developers, it's easy to miss that extra hidden <input> field.
That's why I love if it's built into the framework like Django or Phoenix rather than bolted on or home-rolled.
What do you mean by built-into? The choice of whether to include a token in a form or not is not always trivial for static analysis tools.
On the other hand, if you use some library to handle forms and validation like deform and colander, the CSRF handling is pretty transparent. Also, but validating CSRF on middleware level, you can't forget about it - features relying on POST requests won't work.
What I don't understand is why store it server side? If we make a HTTP Only + secure cookie containing the encrypted and signed csrf value, it can't be obtained by an attacker & the server would require no state or shared cache between instances. It would just compare the HTTP only cookie to the value submitted with the form. On response, expire that cookie.
Is any of this actually needed anymore? Setting the SameSite attribute on the cookie will ensure the browser will not send it for cross-site requests, so... problem solved?
I still can't seem to get good informantion if this should be common usage on something like React SPAs for things like signup forms and other forms publicly POSTing data?
The article below seems to suggest that as long as your api is on a subdomain and is using CORS headers, you should be fine.
However I’m not so sure about this, as I still implement CSRF tokens in my SPAs. (Bit of a habit from my php days) I store the tokens in local storage and pass them through the request headers.
A lot of people have different ideas and methods when it comes to CSRF protection on SPAs. I’d love to hear other people’s opinion and tactics!
Docs are a great way to overview. You never know what the actual implementation is doing and I find that having actual hands on experience helps me solidify the knowledge into relatable experience.
If you don't care why, read the docs. If you want to understand HOW, read the code.
• Cross-Site Request Forgery is dead! (2017): https://scotthelme.co.uk/csrf-is-dead/
• CSRF is (really) dead (2019): https://scotthelme.co.uk/csrf-is-really-dead/
If your use of CSRF tokens is purely for preventing cross-site request forgery (and not things like form expiry or double-submit protection, which are commonly paired with it, for better or for worse) then CSRF tokens are genuinely obsolete and unnecessary, and you should set your SameSite attribute on your cookies to ensure you’re protected against CSRF in the most browsers (meaning all browsers from at least the last couple of years—including IE11 updated within that time, by the way—rather than probably just Chrome at present).