Csurf invalid csrf token Express / nodejs

7.6k views Asked by At

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

1

There are 1 answers

5
Ali Shakiba On BEST ANSWER

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.