JAVASCRIPT
Implement CSRF Protection in Node.js Express Apps with Tokens
Protect your Node.js Express application from CSRF attacks by generating and validating anti-CSRF tokens for form submissions.
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const crypto = require('crypto'); // For generating random tokens
const app = express();
const port = 3000;
// Use session middleware (requires a session store for production)
app.use(session({
secret: 'your_strong_secret_key', // Replace with a strong, unique secret
resave: false,
saveUninitialized: true,
cookie: { secure: false } // Set to true if using HTTPS
}));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// CSRF Token Generation Middleware
app.use((req, res, next) => {
if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') {
// No CSRF token needed for safe methods
return next();
}
// Generate a new CSRF token if one doesn't exist in the session
if (!req.session.csrfToken) {
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
}
res.locals.csrfToken = req.session.csrfToken; // Make token available to templates
next();
});
// CSRF Token Validation Middleware for POST requests
function csrfProtection(req, res, next) {
if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'OPTIONS') {
return next(); // Skip for safe methods
}
const clientToken = req.body._csrf || req.headers['x-csrf-token'];
const sessionToken = req.session.csrfToken;
if (!clientToken || !sessionToken || clientToken !== sessionToken) {
console.error('CSRF token mismatch or missing.');
return res.status(403).send('CSRF token mismatch. Request blocked.');
}
// Token is valid, proceed
next();
}
// --- Routes ---
app.get('/', (req, res) => {
// For demonstration, render a simple form with the token
res.send(`
<h1>Welcome</h1>
<p>Your CSRF token for this session: <strong>${req.session.csrfToken}</strong></p>
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="${req.session.csrfToken}">
<label for="amount">Amount:</label>
<input type="text" id="amount" name="amount" value="100">
<br>
<input type="submit" value="Transfer Money">
</form>
<p>Try inspecting the form to see the hidden token.</p>
<p>To simulate an attack, remove the hidden input field and resubmit.</p>
`);
});
// Apply CSRF protection to routes that modify state
app.post('/transfer', csrfProtection, (req, res) => {
const { amount, _csrf } = req.body;
// In a real app, perform the transfer operation here
res.send(`Transfer of ${amount} successful! (CSRF token: ${_csrf})`);
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
console.log('Access http://localhost:3000 to test the CSRF protection.');
});
How it works: Cross-Site Request Forgery (CSRF) attacks trick users into executing unwanted actions on your web application. This Node.js Express snippet demonstrates CSRF protection using synchronizer tokens. A unique token is generated for each user session and embedded in forms (often as a hidden input) or sent via headers for API requests. On submission, the server verifies if the submitted token matches the one stored in the user's session. If they don't match, the request is rejected, preventing attackers from forging requests on behalf of authenticated users.