Back to blog

Simple CSRF token middleware for express

I’ve been doing some Express development in Typescript recently, and I realised that there are no well-maintained CSRF libraries for Express anymore. Plus, CSRF is actually quite simple to implement and it meant I could avoid adding yet-another dependency to my project.

Here’s the basic implementation. It depends on there already being some form of user sesion (in my case, it’s express-session):

import { Request, Response, NextFunction } from 'express';

export const csrfMiddleware = (req: Request, res: Response, next: NextFunction) => {
    const previousCsrf = req.session.csrf;

    // I've set up a manual dependency injection container with some middleware
    // You can substitute this with whatever library you want to use to
    // generate random strings
    // In my case this is a wrapper for Node.Crypto.randomBytes
    req.session.csrf = req.container.get_random_string(128);

    // Make the token available to templates as a variable
    res.locals.csrf = req.session.csrf;

    if (req.method !== "GET" && (previousCsrf !== req.body["_csrf"] || !previousCsrf)) {
        // Unless the request is a GET request, which doesn't use CSRF
        // compare the CSRF from the request with the token stored in session
        // Send a 403 Forbidden response if they don't match
        // or there was no stored csrf
        return res.sendStatus(403);
    }

    // Move to the next function
    next();
}

It’s a fairly basic implementation, but it hits most of the right notes. The tokens are regenerated on each request, so it’s relatively resilient to brute force attacks. It will reject requests if there is no csrf token in the session, which prevents attacks before a session has been created.

It’s got flaws, naturally: the token is tied to a session ID, for one. The tokens are also not encrypted with any sort of secret so they are, in theory, exposed. But as a first pass it’s a decent start. There’s also an issue with using the back button, as this will no longer work with the regnerated csrf token.

The OWASP CSRF Prevention Cheat Sheet has more information and advice on creating secure CSRF tokens. Some improvements to this approach include: encrypt the token, store it as a cookie with a time range, use SameSite cookie attributes.