krakenjs / lusca

Application security for express apps.
Other
1.79k stars 123 forks source link

Support CSRF black/white listing on URL params #123

Open mjy78 opened 6 years ago

mjy78 commented 6 years ago

We have a scenario where our API is consumed by an Angular app using JWT with cookies for authentication and as such we have CSRF enabled.

Our server also supports validating the access token if provided as a url query parameter. We'd like to be able to blacklist (not perform CSRF) API calls when the access token is provided this way. This will enable us to expose the same API for REST clients.

Could the CSRF blacklist/whitelist feature compare against the req.originalUrl instead of just req.path?

At present it performs a simple indexOf comparison the request to ensure the path starts with the blacklist/whitelist entry. Ideally this could support a regex comparison against the req.originalUrl.

This way we could bypass CSRF when the url contains a JWT access token in the query string by specifying something like:

{
  csrf: {
    angular: true,
    blacklist: '\\[?&]access_token=[A-Za-z0-9\\-_=]+\\.[A-Za-z0-9\\-_=]+\\.[A-Za-z0-9\\-_=]+'
  }
}
linkRace commented 6 years ago

Hi @mjy78 , As I understand, you'd like two features added:

mjy78 commented 6 years ago

That's correct.

Although we've since worked around the need for this feature by initialising lusca with csrf: false, then defining a separate middleware that explicitly calls lusca.csrf, but only after checking that the query string doesn't contain the access token...

var csrf = lusca.csrf({
  angular: true
});

app.use(lusca({
  csrf: false, // Only for web based (AngularJS app) clients - see conditional middleware below
  xframe: 'SAMEORIGIN',
  hsts: {
    maxAge: 31536000, //1 year, in seconds
    includeSubDomains: true,
    preload: true
  },
  xssProtection: true
}));

// To allow non-browser clients to make use of the API without CSRF validation complicating things, 
// we don't perform CSRF validation whenever the "access_token" query parameter is included in
// the url.
var conditionalCSRF = function (req, res, next) {
  if (!req.query.access_token) {
    csrf(req, res, next);
  } else {
    next();
  }
}

app.use(conditionalCSRF);