CSRF protection in ExpressJS

CSRF protection in ExpressJS

We can protect ExpressJS against CSRF attacks using a specific NPM module.

We can protect ExpressJS against CSRF attacks using a specific NPM module.

csurf is a middleware that automatically creates and validates a CSRF token which prevents this type of attack on HTTP POST requests.

We can add middleware to our app like this.

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const csrf = require('csurf');

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(csrf());

The pages of our application must therefore contain the token generated in order for POST requests may pass validation. To do this we can use the object response.locals to share data with the views.

app.use((req, res, next) => {
  res.locals.csrfToken = req.csrfToken();
  next();
});

req.csrfToken() is the method added by the middleware to the request object and is used to generate and retrieve the token for the current request.

At this point we can insert the token as a hidden field in the forms having as attribute name the value _csrf.

<form action="/contact" method="post">
  <input type="hidden" name="_csrf" value="<%= csrfToken %>">
  <!-- ... -->
</form>

If the requests are made via AJAX you can take the same approach used in Laravel, that is, to set a specific meta tag on the pages first.

<meta name="csrf-token" content="<%= csrfToken %>">

So each POST request must have the HTTP header CSRF-Token set to the current token value.

'use strict';

const postRequest = (url, body) => {
    const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    
    return fetch(url, {
        credentials: 'same-origin',
        headers: {
                'CSRF-Token': token   
            },
              method: 'POST',
              body: body
    });
};

How do we handle the error resulting from an invalid token? This middleware raises an error that has the property code set to EBADCSRFTOKEN value. We can then use the ExpressJS error handling middleware.

app.use((error, req, res, next) => {
    if(err.code === 'EBADCSRFTOKEN') {
        return res.sendStatus(403);
    }
    return next(error);
});

As you can see, this middleware is extremely effective in its task and relatively simple to use.