9 ms·
A modern approach to preventing CSRF in Go
- deleted 1y ago[deleted]
- truth_seeker 1y agohttps://simonwillison.net/2025/Oct/15/csrf-in-go/ https://simonwillison.net/2025/Oct/15/csrf-in-go/
- teiferer 1y agoCSRF: Cross-Site Request Forgery From https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF https://developer.mozilla.org/en-US/docs/Web/Security/Attack... In a cross-site request forgery (CSRF) attack, an attacker tricks the user or the browser into making an HTTP request to the target site from a malicious site. The request includes the user's credentials and causes the server to carry out some harmful action, thinking that the user intended it.
- NewJazz 1y agoDo most languages have good support for TLS 1.3 as the client?
- ale 1y agoAre CSRF attacks that common nowadays though? Even if your app is used by the 5% of browsers that don’t set the Origin header the chances of that being exploited are even more miniscule. Besides, most webdevs reach for token-based auth libraries before even knowing how to set a cookie header.
- monster_truck 1y agoYes
- zwnow 1y agoAlso cant you just spoof the origin header?
- kevinyew 1y agoYou can if you want to deliberately CORF yourself for some reason - it's there to protect you, but spoofing it doesn't give you any special access you wouldn't otherwise have. The point is that arbitrary user's browsers out in the world won't spoof the Origin header, which is protecting them from CORF attacks.
- masklinn 1y agoA CSRF is an attack against a logged in user, so has to be mediated via their browser. If you can spoof the origin header of a second party when they navigate to a third party, a CSRF is a complete waste of whatever vulnerability you have found.
- littlecranky67 1y agoCurious about that too. In a modern web-app I always set HttpOnly cookies to prevent them being exposed to anything JavaScript, and SameSite=strict. Especially the later should prevent CSRF.
- jeremyscanvic 1y agoErratum: What I'm saying here only applies for cookies with the attribute SameSite=None so it's irrelevant here, see the comments below. (Former CTF hobbyist here) You might be mixing up XSS and CSRF protections. Cookie protections are useful against XSS vulnerabilities because they make it harder for attackers to get a hold on user sessions (often mediated through cookies). It doesn't really help against CSRF attacks though. Say you visit attacker.com and it contains an auto-submitting form making a POST request to yourwebsite.com/delete-my-account. In that case, your cookies would be sent along and if no CSRF protection is there (origin checks, tokens, ...) your account might end up deleted. I know it doesn't answer the original question but hope it's useful information nonetheless!
- RagingCactus 1y agoThe SameSite cookie flag is effective against CSRF when you put it on your session cookie, it's one of its main use cases. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/... for more information. SameSite=Lax (default for legacy sites in Chrome) will protect you against POST-based CSRF. SameSite=Strict will also protect against GET-based CSRF (which shouldn't really exist as GET is not a safe method that should be allowed to trigger state changes, but in practice some applications do it). It does, however, also make it so users clicking a link to your page might not be logged in once they arrive unless you implement other measures. In practice, SameSite=Lax is appropriate and just works for most sites. A notable exception are POST-based SAML SSO flows, which might require a SameSite=None cookie just for the login flow.
- jeremyscanvic 1y agoThanks for correcting me - I see my web sec knowledge is getting rusty!
- tankenmate 1y agoI would never rely on headers such as "Sec-Fetch-Site"; having security rely on client generated (correct) responses is just poor security modelling (don't trust the client). I'll stick to time bounded HMAC cookies, then you're not relying on client properly implementing any headers and it will work with any browser that supports cookies. And having TLS v1.3 should be a requirement; no HTTPS, no session, no auth, no form (or API), no cookie. And having HSTS again should be default but with encrypted connections and time bounded CSRF cookies the threat window is very small.
- jebronie 1y agoI don't understand why your post is flagged. You are 100% right. The point of CSRF protection is that -you can't trust the client-. This new header can just be set in curl, If I understand correctly. Unlimited form submissions here I come!
- eptcyka 1y agoCSRF protects the user by not allowing random pages on the web using resources from a target website, without the user being aware of this. It only makes sense when serving people using browsers. It is not a defense against curl or skiddies.
- nchmy 1y agoTo elaborate/clarify a bit, we defend against curl with normal auth, correct? Be it session cookies or whatever. That plus origin/Sec-Fetch-Site (and tls, secure cookies, hsts) should be reasonable secure, no?
- tankenmate 1y agoindeed, you need some form of CSRF, but the Sec-Fetch-Site is primarily focused on keeping a browser secure, not the server. Having said that it's nice defence in depth for the server as well but not strictly required as far as the server is concerned.
- nmadden 1y agoEnforcing TLS 1.3 seems like a roundabout way to enforce this. Why not simply block requests that don’t have an Origin/Sec-Fetch-Site header?
- nchmy 1y agoI don't understand - the article is literally about origin/Sec-Fetch-Site
- nmadden 1y agoThe article has a whole section about requiring those headers by forcing the use of TLS 1.3 — the theory being that browsers modern enough to support 1.3 are also modern enough to support the headers. But why not just enforce the headers?
- kokada 1y agoIf your case is just supporting browsers and not things like curl this seems fine. But when the headers are not set the CSRF protections are "disabled" exactly to support this case, that you may want to do this request using something like curl.
- nmadden 1y agoI guess. But it would only impact you if you’re using cookies with curl (I assume the middleware is only applied to requests with cookies?) — and it seems pretty easy to add a -H ‘sec-fetch-site: none’ in that case.
- nchmy 1y agoI see what you mean. You were saying why tls in addition to Sec-Fetch-Site. The sibling comment seems to have addressed it
- jodal 1y agohttps://words.filippo.io/csrf/ https://words.filippo.io/csrf/
- cientifico 1y agoKilling all the fun. Remember when you could trick a colleague into posting in Twitter, Facebook... by just sending a link? CSRF fixes are great for security - but they've definitely made some of the internet's harmless mischief more boring
- vulk 1y agoOn a side note Alex books are a breath of fresh air for someone who is learning. They are always updated to the latest version of Go and if there is something new the old code base is updated and the new concepts introduced while you are being notified and send the new version of the book. I never seen that before, all the other learning sources that I have are just abandoned, often there will be something that brakes and you have to spend good amount of time to figure out how to fix it, which can just discourage you to go on. Kudos to Alex that is how it should be done.
- Zababa 1y ago"cop" as an abbreviation for "cross-origin protection" is delightful
- makkes 1y agoThe code he provides doesn't compile and needs to be changed like so: --- main_before.go 2025-10-15 09:56:16.467115934 +0200 +++ main.go 2025-10-15 09:52:14.798134654 +0200 @@ -13,8 +13,10 @@ slog.Info("starting server on :4000") + csrfProt := http.NewCrossOriginProtection() + // Wrap the mux with the http.NewCrossOriginProtection middleware. - err := http.ListenAndServe(":4000", http.NewCrossOriginProtection(mux)) + err := http.ListenAndServe(":4000", csrfProt.Handler(mux)) if err != nil { slog.Error(err.Error()) os.Exit(1)
- alex_edwards 1y agoThanks for pointing this out, what a facepalm. I've fixed it in the post.
- dorianmariecom 1y agorails solved this a while ago ;)
- nchmy 1y agoI don't use rails. How did they solve it?
- brokegrammer 1y ago>Have we finally reached the point where CSRF attacks can be prevented without relying on a token-based check (like double-submit cookies)? Rails uses a token-based check, and this article demonstrates token-less approach. Rails didn't solve CSRF btw, the technique was invented long before Rails came to life.
- nchmy 1y agoYes, I assumed this is what they were ignorantly pointing towards. Indeed, Csrf tokens are an ancient concept. WordPress, for example, introduced nonces a couple years before rails. Though, it does appear that rails might have been thr first to introduce csrf protection in a seemingly automated way.
- brokegrammer 1y agoTrue, it does seem like Rails introduced configuration-free token based CSRF protection, which "solved" CSRF for traditional server rendered apps. I believe the new technique is easier to use for SPA architectures because you no longer need to extract the token from a cookie before adding it to request headers.
- nchmy 1y agoI deeply appreciate this thorough review of CSRF protection via headers. I've been looking into the topic to see if I can get rid of csrf tokens, and it seems like I can now - if I ignore/don't care about the 5% of browsers that don't support the required headers. It makes me wonder though - most browser APIs top out around 95% coverage on caniuse.com. What are these browsers/who are these people...? The modern web is very capable and can greatly simplify our efforts if we ignore the outliers. I'm inclined to do so. But am also open to counterarguments
- anal_reactor 1y agoFrom business perspective it makes a lot of sense to just drop that bottom 5%. Actually, many businesses support Chrome only, they don't even support Firefox. Technological counterargument though is that you should allow people to tinker and do weird shit. Once upon a time tech wasn't about maximizing stock value, it was about getting Russian game crack to work, and making Lora's boobs bigger. Allowing weird shit is a way to respect the roots of modern tech, and allow hobbyists to tinker.
- nchmy 1y agoThanks for confirming. I don't know that it has to be framed as a "business perspective" though. I'm a solo dev for a non-profit project, so ignoring the 5% is just a matter of pragmatism. I most defintiely do not care about tinkerers, and in fact would generally classify them as something akin to attackers. I just want to allow as many people to use the app as possible, while keeping things simple and secure.
- cryptonym 1y agoEmpathy and accessibility. Does it make sense to have a ramp in front of your shop for < 5% customers?
- nchmy 1y agoMy question, though, is who are the 5% of users in this case who are using some arcane browsers? Surely that's largely a choice, physical disabilities are not. It doesn't seem unreasonable to say to those folks "were evidently not using the same web"
- rana762 1y ago[dead]
- hmcamp 1y agoWould have like to have seen a complete working example at the end that addresses all the concerns
- androiddrew 1y agoAlex has two books that I can’t recommend more. Let’s Go and Let’s Go Further really cemented Golang for me.
- todotask2 1y agoDo we still need _HOST?