15

I'm writing a small web app with Node.js using the Express framework. I'm using the csrf middleware, but I want to disable it for some requests. This is how I include it in my app:

var express = require('express');
var app = express();

app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.cookieSession({secret: 'secret'}));
app.use(express.csrf());

I want to set a POST route without the csrf control.

Gio Polvara
  • 23,416
  • 10
  • 66
  • 62

5 Answers5

32

There are several possible approaches. You basically need to understand what is the simplest and most correct rule to decide whether or not to use the csrf middleware. If you want csrf most of the time, except for a small whitelist of request patterns, follow the example in this answer I have about conditional logging middleware (copied below for convenience).

var express = require("express");
var csrf = express.csrf();
var app = express.createServer();

var conditionalCSRF = function (req, res, next) {
  //compute needCSRF here as appropriate based on req.path or whatever
  if (needCSRF) {
    csrf(req, res, next);
  } else {
    next();
  }
}

app.use(conditionalCSRF);
app.listen(3456);

Another approaches could be only using the middleware on a certain path like app.post('/forms/*', express.csrf()). You just want to find an expressive way to make it clean when the middleware will or will not be used.

Community
  • 1
  • 1
Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • please note that if you use csurf and not express.csrf, this won't work. See http://stackoverflow.com/questions/24992139/node-js-use-csurf-conditionally-with-express-4 – Cédric NICOLAS Nov 04 '15 at 22:54
  • See the following issue that says it doesn't work..Has any thing changed in recent versions that makes it not to work?? https://github.com/expressjs/csurf/issues/23 – Naga Kiran Nov 06 '15 at 15:38
  • Wonderful! Saved my butt. – David Boyd Jan 23 '16 at 22:37
  • could anyone please tell me how you peoples compute needCSRf – Vishnu Jun 19 '18 at 08:54
  • The question asker said they wanted to disable CSRF for "some requests" without specifying which requests or criteria, so my answer presumes they have some application-specific criteria for which requests do or do not need CSRF. If you have a standard application, using CSRF always is probably correct. – Peter Lyons Jun 19 '18 at 14:40
2

Since Express middleware executes in order, you could always put your statements above the csrf() statement in the code.

Like this:

app.get '/ping', (req, res) -> res.status(200).end()
app.use csrf()

Express will return before your csrf token gets set. For very small numbers of endpoints (I just have one that fits this category), I've found this to be a cleaner solution.

Also, as of this writing, the code for the above answer would look like this:

customCsrf = (req, res, next) ->
  if req?.url isnt '/ping'
    return csrf()(req, res, next)
  else
    return next()

app.use customCsrf

That extra (req, res, next) tripped me up for awhile, so hope this helps someone.

Kevin
  • 69
  • 1
  • 3
1

dailyjs.com has a good article about csrf and express. It basically works like this:

use the csrf middleware:

app.configure(function() {
  // ...
  app.use(express.csrf());
  // ..
});

create a custom middleware that sets the local variable token to the csrf value:

function csrf(req, res, next) {
  res.locals.token = req.session._csrf;
  next();
}

use your custom middleware in every route you want:

app.get('/', csrf, function(req, res) {
  res.render('index');
});

in your form create a hidden field that holds the csrf value:

form(action='/contact', method='post')
  input(type='hidden', name='_csrf', value=token)
zemirco
  • 16,171
  • 8
  • 62
  • 96
  • where do you actually validate the token? – chovy Nov 22 '12 at 22:04
  • validation is done by the csrf middleware on `POST` requests. see the [docs](http://www.senchalabs.org/connect/csrf.html) – zemirco Nov 22 '12 at 22:12
  • i don't see anything. I would expect if ( token == req.session._csrf ) somewhere. – chovy Nov 22 '12 at 22:17
  • 2
    That doesn't do selective csrf on a per route basis. It only provides a convenience to add the token where needed. Omitting the 'csrf' middleware will throw a 403 – cyberwombat Dec 12 '13 at 22:57
1

Use the middleware at express app level adding every HTTP method to the ignored list, to ensure that the protection does not verify by default.

E.g.

const ignoredMethods = [
    'GET',
    'HEAD',
    'POST',
    'PUT',
    'DELETE',
    'OPTIONS'
]

const csrfInit = csurf({ignoredMethods, cookie: true });
app.use(csrfInit);

This will inject the csrfToken() method into each request object allowing the setup of a hidden field or consumable cookie by the application.

Then add a protected version in your as middleware to desired routes, and ignore the ones that do not require it.

E.g. Protected

const csrfProtection = csurf({ cookie: true });


router.post('/api/foo', csrfProtection, (req, res, next) => ...

E.g. Unprotected

const csrfProtection = csurf({ cookie: true });


router.post('/api/foo', (req, res, next) => ...

That worked for me.

0
const csrf = require("csurf");
const ROOT_IGNORE_LIST = ["/api/authenticate"];
const csrfMiddleware = csrf({
      cookie: true,
      ignoreMethods: ["GET", "HEAD", "OPTIONS"],
});

// Create middleware to check request url
app.use((req, res, next) => {
  if (ROOT_IGNORE_LIST.includes(req.url)) {
    next();
  } else {
    csrfMiddleware(req, res, next);
  }
}).use("/api", routes);