6

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

Community
  • 1
  • 1
pedrommuller
  • 15,741
  • 10
  • 76
  • 126

1 Answers1

4

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.

Ali Shakiba
  • 20,549
  • 18
  • 61
  • 88
  • I removed my middleware, I and change the configuration to csrf({ cookie: true }) to create its own cookie, however, I'm still getting the issue, thanks for the help! – pedrommuller Jun 10 '15 at 13:58
  • So please update your question with the new code and new debugging info, including where you use req.csrfToken() or res.locals.csrftoken. – Ali Shakiba Jun 10 '15 at 15:57
  • I updated the question, now I got a slightly different scenario – pedrommuller Jun 10 '15 at 16:00
  • 2
    How do you set the token in your requests? You should use `req.csrfToken()` by assigning it to view locals, either `res.locals` as you have done in your middleware, or `res.render(view, locals)`. Currently you are using cookie/secret value for token. – Ali Shakiba Jun 10 '15 at 16:13
  • I fixed it by passing the req.csrfToken() to the view – pedrommuller Jun 11 '15 at 21:45