Welcome to this guide on securing your Express applications against Cross-Site Request Forgery (CSRF) attacks. Imagine hosting an exclusive party—you issue personalized invitations (tokens) to each guest so nobody can sneak in with a forged invite. CSRF protection works similarly: each request from your frontend to your backend must present valid “invitations” (tokens), making it much harder for attackers to impersonate a logged-in user.
In this reading, you’ll learn:
csurf packageGET requestBy the end, you’ll have a clear roadmap for keeping your application safe from one of the most common exploits on the web.
Cross-Site Request Forgery (CSRF) tricks a logged-in user’s browser into making unintentional or malicious requests to your server. The user unwittingly carries out actions that seem legitimate because they’re authenticated. For instance, an attacker might embed a hidden form in a malicious page that, when clicked, sends money from the user’s bank account to the attacker’s.
If you need a refresher, revisit the previous reading about CSRF attacks—learning how they work helps you understand why these prevention steps are necessary.
csurf Middleware
First, you’ll configure your Express application to automatically generate and verify CSRF tokens. Think of csurf as a bouncer at your party: it hands each guest a personalized pass (token), then checks that pass on every subsequent visit to ensure it’s still valid.
csurf:
npm install csurf
csurf in your Express server:
const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const express = require('express');
const app = express();
// Parse cookies
app.use(cookieParser());
// Set up CSRF protection middleware
app.use(
csrf({
cookie: {
secure: process.env.NODE_ENV === 'production',
sameSite: process.env.NODE_ENV === 'production' && 'Lax',
httpOnly: true
}
})
);
// Now every request to your server will receive two cookies:
// 1) Encrypted CSRF cookie (csurf)
// 2) Decrypted XSRF-TOKEN cookie
// ... your routes here
const port = 3000;
app.listen(port, () => {
console.log('Server listening on port', port);
});
Once csurf is set up, Express will generate two cookies:
csurf (HTTP-only, Same-Site, etc.)These two cookies function like matching puzzle pieces—the server can verify they belong together, preventing outside parties from forging them.
Next, your frontend must add the decrypted token (from the XSRF-TOKEN cookie) to the headers of every request that changes data (e.g., POST, PUT, DELETE). That’s like including your personalized invitation in each request, proving you’re an authorized guest.
// A simplified example of reading document.cookie in JavaScript
const cookies = {};
// document.cookie is a string: "key1=value1; key2=value2; ..."
document.cookie.split(';').forEach((pair) => {
const [key, value] = pair.trim().split('=');
cookies[key] = value;
});
// Retrieve the decrypted CSRF token
const csrfToken = cookies['XSRF-TOKEN'];
// Include it in any non-GET request
fetch('http://localhost:3000/some-data', {
method: 'POST',
headers: {
'XSRF-Token': csrfToken
},
body: JSON.stringify({ example: 'payload' })
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error(err));
Here’s the flow:
csurf cookie (HTTP-only) and the decrypted XSRF-TOKEN cookie (readable by JavaScript).XSRF-TOKEN cookie: Storing the value in a variable (e.g., csrfToken).XSRF-Token: [token value] in the headers: For POST, PUT, DELETE, or any requests that need protection.XSRF-TOKEN matches the encrypted csurf cookie.
By design, GET requests typically don’t alter data, so CSRF checks are more relevant for POST, PUT, DELETE, and other requests that change state or process sensitive info.
Your server will expect:
XSRF-TOKEN in the headers, named something like XSRF-Token or X-CSRF-Token.csurf cookie still attached to the request (automatically sent by the browser for same-site cookies).
If these two tokens do not match, csurf rejects the request. Only when both tokens align does the request go through.
Consider the backend as a locked door with two keyholes:
XSRF-TOKEN) can open.csurf cookie’s encrypted signature.If both keys fit, the door opens. If either key is missing or incorrect, the door stays locked—this prevents attackers from picking just one of the locks and waltzing inside.
You now know how to shore up your Express app against CSRF attacks:
csurf on the backend to generate the necessary cookies.XSRF-TOKEN header to every non-GET request on the frontend.These measures significantly reduce the risk that a malicious site can force an authenticated user to take unwanted actions. While no security system is perfect, CSRF tokens form an essential part of your overall defense strategy in modern web applications.
Congratulations—you’re well on your way to building safer, more secure Express apps!