Tech News
← Back to articles

A modern approach to preventing CSRF in Go

read original related products more articles

My new book guides you through the start-to-finish build of a real world web application in Go — covering topics like how to structure your code, manage dependencies, create dynamic database-driven pages, and how to authenticate and authorize users securely.

Go 1.25 introduced a new http.CrossOriginProtection middleware to the standard library — and it got me wondering:

Have we finally reached the point where CSRF attacks can be prevented without relying on a token-based check (like double-submit cookies)? Can we build secure web applications without bringing in third-party packages like justinas/nosurf or gorilla/csrf ?

And I think the answer now may be a cautious “yes” — so long as a few important conditions are met.

If you want to skip the explanations and just want to see what those conditions are, you can click here.

The http.CrossOriginProtection middleware

The new http.CrossOriginProtection middleware works by checking the values in a request's Sec-Fetch-Site and Origin headers to determine where the request is coming from. It will automatically reject any non-safe requests that are not from the same origin, and will send the client a 403 Forbidden response.

The http.CrossOriginProtection middleware has some limitations, which we'll discuss in a moment, but it is robust and simple to use, and a great addition to the standard library.

How it works Modern browsers automatically include the Sec-Fetch-Site header in requests. This header indicates the relationship between the origin of the page making the request, and the origin of the page being requested. Two pages are considered to have the same origin if their scheme, hostname and port (if present) exactly match, in which case the browser will include a Sec-Fetch-Site: same-origin header in the request. If the two pages don't have the same origin, the Sec-Fetch-Site header will be set to a different value to indicate this, and http.CrossOriginProtection will reject the request. If no Sec-Fetch-Site header is present, http.CrossOriginProtection will fall back to checking the Origin header. Specifically, it will compare the request's Origin header and Host header to see if they match. If they don't match, then it considers the request to not be from the same origin and it will reject it. If neither the Sec-Fetch-Site nor Origin headers are present, then it assumes the request is not coming from web browser and will always allow the request to proceed. The checks described above only take place on requests with non-safe methods ( POST , PUT , etc.). Requests with safe HTTP methods ( GET , OPTIONS , etc.) are always allowed to proceed. If you're interested in learning more about the design and decision making behind http.CrossOriginProtection , the original proposal by Filippo Valsorda is an excellent read.

At its simplest, you can use it like this:

... continue reading