Hacker News new | past | comments | ask | show | jobs | submit login
Close Look at CSRF Tokens (denvaar.github.io)
65 points by lobo_tuerto on May 7, 2020 | hide | past | favorite | 24 comments



Related:

• 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).


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.


Subdomain hijacking is not rare for the simple reason that websites are built by marketing departments. E.g., here’s Hanno Böck tweeting about a subdomain takeover he found at Kaspersky just recently: https://twitter.com/hanno/status/1257958739132514304 There’s a whole cottage industry of people finding these vulnerabilities on a very regular basis: https://www.hackerone.com/blog/Guide-Subdomain-Takeovers


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.


Unfortunately there's still iframes, that don't play well with SameSite


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.


Big Django user. Isn't it still required that you add the {% csrf_token %} tag to your forms?

That is, the protection will be on. But the way to be allowed in by the gate is not on by default. You have to remember to add the tag.

Which is why I'm so excited to just switch to SameSite once there's enough browser usage...


My Django is a little rusty but I think now requests will return 403s by default if you forget to include the csrf_token tag: https://docs.djangoproject.com/en/3.0/ref/csrf/#rejected-req...

Whereas the hand-rolled CSRF scheme I've inherited will fail silently


That's what I mean. If you forget to include the token on your app, it will fail. You have to remember to call {% csrf_token %} in every template.

Back in the day, the middleware scanned your response and injected it next to each </form> tag. A hack and dirty for sure, but removed that burden.


It will fail securely, which is what you want. The alternative is to have it fail insecurely and bypass validation for everything.

In the latest versions the framework sets the SameSite header properly, so you don't need the CSRF middleware at all (you can just remove it).


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.

Does anyone know of a downside to that?



Ah! Thanks, I've been looking for the exact definition!


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?


CSRF protection isn't needed after SameSite, nope.


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!

Feel free to correct me on anything.

Article: https://medium.com/tresorit-engineering/modern-csrf-mitigati...


Reverse engineering seems an odd way to learn about this when good documentation is available, e.g. https://docs.djangoproject.com/en/3.0/ref/csrf/


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.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: