Understanding CSRF vulnerabilities
📘 What is CSRF vulnerability?
CSRF is a type of attack where a malicious site tricks a user’s browser into making an unwanted request to a different site where the user is authenticated. It exploits the trust that a site has in the user’s browser.
Imagine you’re logged into your bank account in one tab. In another tab, you visit a malicious site that silently sends a request to your bank to transfer money, using your credentials. That’s CSRF.
🧪 Demonstration
Here’s a simplified vulnerable Go web app:
package main
import ( "fmt" "net/http")
func transferHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { amount := r.FormValue("amount") to := r.FormValue("to") fmt.Fprintf(w, "Transferred %s to %s", amount, to) } else { w.Write([]byte(` <form method="POST" action="/transfer"> <input name="amount"> <input name="to"> <input type="submit" value="Transfer"> </form> `)) }}
func main() { http.HandleFunc("/transfer", transferHandler) http.ListenAndServe(":8080", nil)}
This app blindly accepts POST requests without verifying the origin or user intent.
💣 Exploiting the vulnerability
An attacker could craft a malicious HTML page like this:
<form action="http://victim.com/transfer" method="POST"> <input type="hidden" name="amount" value="1000"> <input type="hidden" name="to" value="attacker"> <input type="submit" value="Click me for a surprise!"></form><script>document.forms[0].submit();</script>
If the victim is logged into victim.com, this form auto-submits and transfers money to the attacker—without the user knowing.
🛡️ How to prevent CSRF attacks
✅ Use CSRF Tokens
Generate a unique token per user session and embed it in forms. On form submission, validate the token against the one stored in the session :
// Generate tokenfunc generateCSRFToken() string { b := make([]byte, 32) rand.Read(b) return base64.StdEncoding.EncodeToString(b)}
Then, we pass the CSRF_TOKEN in the form. The attacker should not be able to guess the CSRF_TOKEN
of the user.
<form method="POST" action="/submit"> <input type="hidden" name="csrf_token" value="{{ .CSRF_TOKEN }}"> <input name="amount"> <input name="to"> <input type="submit" value="Transfer"></form>
On the server side, verify that the submitted token matches the one stored in the user’s session. This ensures the request is legitimate.
Modern framework include this functionality by default:
- https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-form
- https://laravel.com/docs/12.x/csrf#csrf-x-csrf-token
- https://symfony.com/doc/current/security/csrf.html
- https://docs.adonisjs.com/guides/security/securing-ssr-applications#csrf-protection
- https://guides.rubyonrails.org/security.html#required-security-token
✅ Use SameSite Cookies
Set cookies with SameSite=Strict
or Lax
to prevent cross-origin requests.
http.SetCookie(w, &http.Cookie{ Name: "session_id", Value: "abc123",
SameSite: http.SameSiteStrictMode, // or http.SameSiteLaxMode. Don't use SameSiteNoneMode
Secure: true, // ensures cookie is sent over HTTPS HttpOnly: true, // prevents access from JavaScript Path: "/",})
The SameSite
property on cookie can have multiple values:
- Strict: cookie is only sent in a first-party context (i.e., same site). Best for sensitive cookies.
- Lax: cookie is sent with top-level navigations and GET requests initiated by third-party sites.
- None: cookie is sent in all contexts, including cross-origin.
Use SameSite=Strict for maximum protection, but be aware it may block legitimate cross-site usage (e.g., from third-party services).
SameSite=Lax
offers a balance by allowing top-level navigation
while still blocking most cross-origin requests.
Understanding XSS vulnerabilities
In this article, we will explore how XSS vulnerabilities work and how to prevent them
Understanding SQL injection vulnerabilities
In this article, we will explore how SQL injection vulnerabilities work and how to prevent them
Practice code with the "Quick Sort" algorithm
Enhance your coding skills by learning how the Quick Sort algorithm works!
The SOLID/STUPID principles
Learn what are the SOLID and STUPID principles with examples
Create a Docker Swarm playground
Let's create Docker Swarm playground on your local machine
Create an Ansible playground with Docker
Let's create an Ansible playground with Docker
HashiCorp Vault - Technological watch
Learn what is HashiCorp Vault in less than 5 minutes !
Setup a Kubernetes cluster with K3S, Traefik, CertManager and Kubernetes Dashboard
Let's setup step by step our own K3S cluster !