CSRF attacks explained — and how to stop them
A CSRF (Cross-Site Request Forgery) attack tricks an authenticated user into making a request to your app without knowing it.
Here's the scenario: you're logged into your bank. The session cookie is set. You visit a malicious website. That site contains an invisible form that points to your bank's transfer endpoint. The form auto-submits in the background. Your browser sends the request — including the session cookie — because that's how cookies work. The bank sees an authenticated request and processes the transfer.
Why cookies aren't enough
Cookies are sent automatically by the browser on any request to the matching domain. They don't prove the request was intentional or came from your app's UI.
CSRF tokens
The standard protection is a CSRF token — a random value generated per-session that:
- Gets included in every form as a hidden field
- Gets verified server-side before processing the form
An attacker can forge the request but can't know the CSRF token (it's not in a cookie, it's not accessible from another origin).
SameSite cookies
Modern browsers support the SameSite cookie attribute. Setting it to Strict or Lax prevents the browser from sending the cookie on cross-site requests, which stops most CSRF attacks.
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnlyIn Next.js
If you're using Next.js API routes, you can check the Origin or Referer header against your app's domain. For form submissions, use a library like csrf or rely on the framework's built-in protection if you're using a full-stack meta-framework.