CSRF Protection #

Build a secure Go web server without external dependencies — just the standard library.

In this short example, you’ll learn how to protect your web server from Cross-Site request forgery (CSRF) attacks. We'll be using the newly introduced http.NewCrossOriginProtection() module. By the end, you’ll know how to implement CSRF protection.

Unsecure Banking #

Imagine you:

  1. Are logged in to your bank account in your browser
  2. Click on an offer link from your bank in your email inbox

The link redirects you to your bank's website, but the offer page turns out to be dead.

A week later, you find out that money was sent to another bank account that you don't know. This happened because the link was malicious.

The Relieve #

We can protect our users by rejecting non-safe cross-origin browser requests. The http.NewCrossOriginProtection() will help us do this. It detects cross-origin requests in the following ways: 1 2

Import the Package #

To enable this protection, we have to import the required package:

import "net/http"

Setup the CSRF Protection #

We can initialize the http.NewCrossOriginProtection() and wrap our Multiplexer (mux) in it. If you don't know how to setup a simple web server, please take a look at this article.

antiCSRF := http.NewCrossOriginProtection()
handler := antiCSRF.Handler(mux)
CrossOriginProtection implements protections against Cross-Site Request Forgery (CSRF) by rejecting non-safe cross-origin browser requests.

We can also add other trusted origins with antiCSRF.AddTrustedOrigin("https://example.com"). The CSRF protection will now allow requests coming from https://example.com.

Complete Example #


package main

import (
	"errors"
	"fmt"
	"net/http"
	"os"
)

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("POST /{$}", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, I'm protected against CSRF attacks!")
	})

	antiCSRF := http.NewCrossOriginProtection()

	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", 8080),
		Handler: antiCSRF.Handler(mux),
	}

	err := srv.ListenAndServe()
	if !errors.Is(err, http.ErrServerClosed) {
		os.Exit(1)
	}
}
Simple web server that is protected against CSRF attacks.

Try It with curl #

Once your server is running, you can test it using:

curl --data "ok" -H "sec-fetch-site:same-origin" localhost:8080

You should see this response:

Hello, I'm protected against CSRF attacks!

Let's try a different origin and host:

curl --data "ok" \
  -H "origin:https://example.com" \
  -H "host:tobiasgleiter.de" \
  localhost:8080

You should see this response:

cross-origin request detected, and/or browser is out of date: Sec-Fetch-Site is missing, and Origin does not match Host

The server did reject the host because the Origin header didn't match the Host.

Contributions

Special thanks to Patrick Henry Winston his book Make It Clear was instrumental in shaping this article. Looking ahead, I’ll be focusing on two projects: Beago, a Go framework for building LLM-powered applications, and Vona, a minimalist and lightweight starter kit that that utilises Pico for beautiful plug-and-play landing page UI blocks.

Read more

Resources #

  1. antonz.org (8/13/25)
  2. pkg.go.dev (8/13/25)