CSRF无效的CSRF令牌Express/nodejs。

6
我有一个奇怪的行为,当我的页面加载时,我只会得到一个错误,基本上是'EBADCSRFTOKEN'。我一直在尝试找出它为什么只在第一次加载页面时发生,如果我点击刷新并获取一个新的令牌,一切都正常。
当我删除csurf cookie,点击刷新并获取一个新的令牌时,同样的情况也会发生,但第一次总是失败,我不确定为什么期望的字符串和令牌都不匹配。
以下是代码片段(我正在使用MEANJS堆栈):
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();
    });
};

令牌的不同值:

Cookie

fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA

req.csrfToken()(在中间件请求中)

fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA

期望值(在csurf库中)

fgeHcu6v-T9CuTWL8hVGHMtSskeh0yzqaP0k

令牌(在csurf库中)

fgeHcu6v-hgdCMuRjnmE9BYV_QrvrfzwJoeA

看起来期望值与令牌相似,只是在破折号后略有不同,有什么想法吗?

更新:

基本上,我按照@shakiba的建议去掉了自定义中间件,让csurf库处理它。

我改变了配置为:

app.use(csrf({ cookie: true }));

现在我得到了一个名为_csrf的cookie,现在问题有点不同,令牌值与库中的秘密令牌相同,因此当库"转换"秘密令牌成为预期的令牌时它们不匹配。

以下是一些示例值:

Cookie BDir8-6hkdy-_YsXNb305IIx

Secret BDir8-6hkdy-_YsXNb305IIx

Token BDir8-6hkdy-_YsXNb305IIx

Expected BDir8-zbwt4-K_Uv8t1TtmxxctkfcMN1M

1个回答

4
我相信您没有正确地使用csurf,csurf会为您设置cookie,您不应该自己设置它,且其值与csrfToken()的值不同。从文档和源代码中可以了解到,csrfToken()的值是使用csurf为cookie设置的值生成的,因为它们通过state来缓解BREACH攻击。我简化了csurf的版本,仅使用cookie,并未处理BREACH攻击,因为BREACH攻击对我来说是一个独立的问题,应使用独立的模块/库进行解决。我将在github上分享这个版本,如果您喜欢,可以使用它。

我移除了我的中间件,并将配置更改为csrf({ cookie: true })以创建自己的cookie,但是我仍然遇到了问题,感谢您的帮助! - pedrommuller
所以请使用新代码和新的调试信息更新您的问题,包括您在哪里使用了req.csrfToken()或res.locals.csrftoken。 - Ali Shakiba
我更新了问题,现在我的情况略有不同。 - pedrommuller
2
你如何在请求中设置令牌?你应该使用 req.csrfToken() 将其分配给视图本地变量,可以像你在中间件中所做的那样将其分配给 res.locals,或者在 res.render(view, locals) 中。目前你正在使用 cookie/secret 值作为令牌。 - Ali Shakiba
我通过将req.csrfToken()传递到视图中来解决了这个问题。 - pedrommuller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接