I have this odd behavior I get an error just the first time my page loads, basically is 'EBADCSRFTOKEN' I've been trying to figure it out why it happens only the first time the page loads, if I hit refresh and get a new token everything works fine.
the same scenario happens when I delete the csurf cookie, hit refresh and I get a new token, but the first time always fail I'm not sure why both the expected string and the token don't match.
a snippet of the code (I'm using MEANJS stack):
app.use(busboy());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json({limit: '50mb'}));
app.enable('jsonp callback');
var cp = cookieParser;
app.use(cp());
var mStore = new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
});
app.use(session({
secret: config.sessionSecret,
store: mStore,
cookie: {httpOnly: false},
key:config.cookieKey,
}));
app.use(csrf());
//setting up a middleware
var middlewareFiles = [
'csrf-rule.server.js',
'secure-routes.server.js'
];
middlewareFiles.forEach(function(routeSecure){
require(path.resolve('./app/middleware/'+routeSecure))(app);
});
app.use(function(err, req, res, next) {
if (!err) return next();
if(err.code === 'EBADCSRFTOKEN'){
res.json(484, {data: 'invalid csrf token.'});
return;
}
// Error page
res.status(500).render('500', {
error: err.stack
});
});
Middleware:
module.exports = function(app) {
app.use(function(req, res, next){
res.cookie('x-xsrf-token', req.csrfToken());
res.locals.csrftoken = req.csrfToken();
next();
});
};
Different values for the token:
Cookie
fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA
req.csrfToken() (in middleware request)
fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA
Expected (in csurf library)
fgeHcu6v-T9CuTWL8hVGHMtSskeh0yzqaP0k
Token (in csurf library)
fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA
seems like the expected is similar to the token and they differ just after the dash, any ideas?
UPDATE:
Basically, I followed @shakiba recommendation I removed my custom middleware and I let the csurf library handle it.
I changed the configuration to:
app.use(csrf({ cookie: true }));
now I get a cookie named _csrf, now the issue is a little bit different, the token value is the same as the secret token in the library, so when the library "converts" the secret token to be the expected token they don't match.
These are some example values:
Cookie BDir8-6hkdy-_YsXNb305IIx
Secret BDir8-6hkdy-_YsXNb305IIx
Token BDir8-6hkdy-_YsXNb305IIx
Expected BDir8-zbwt4-K_Uv8t1TtmxxctkfcMN1M
I believe you are not using csurf correctly, csurf sets the cookie for you, you should not set it yourself, and its value is different from csrfToken() value. As far as I understand from docs and source code csrfToken() value is generated using the value that csurf sets for the cookie, as they state to mitigate BREACH attack.
I have made simpler version of csurf that only uses cookies and does not do anything about BREACH attack, because BREACH attack looks to me to be an independent concern that should be addressed in an independent module/library. I will share it on github so you can use it if you like.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With