在nodejs(Express)中使用CSURF的“无效的csrf令牌”。CSRF令牌适用于第一个请求,但对所有其他请求都给出错误
Posted
技术标签:
【中文标题】在nodejs(Express)中使用CSURF的“无效的csrf令牌”。CSRF令牌适用于第一个请求,但对所有其他请求都给出错误【英文标题】:"Invalid csrf token" using CSURF in nodejs(Express).CSRF token works fine for first request but give error for all other requests 【发布时间】:2019-12-05 20:38:20 【问题描述】:我正在使用 NodeJS Express 和 passport.js 进行用户身份验证。我已经在我的登录表单中实现了 csrf 身份验证。当我第一次进入登录页面时,Csrf 令牌工作正常,但是当我注销并重定向到登录页面时,我收到错误“Invalid csrf token”。
我已经尝试使用 res.render(csrf: req.csrfToken()); 将 csrf 令牌显式传递给视图(EJS 模板引擎);但它不起作用。
const path = require('path');
const sequalize = require('./utils/database');
const localStrategy = require('passport-local').Strategy;
//const User = require('../models/user');
const bycrypt = require('bcryptjs');
const express = require('express');
const session = require('express-session');
const sessionStore = require('express-mysql-session')(session);
const passport = require('passport');
const bodyParser = require('body-parser');
const csrf = require('csurf');
const flash = require('connect-flash');
const User = require('./models/user');
const app = express();
var options =
host: 'localhost',
port: 3306,
user: 'root',
password: '',
database: 'lab'
;
var mysqlStore = new sessionStore(options);
app.set('view engine', 'ejs');
app.set('views', 'views');
app.use(flash());
app.use(bodyParser.urlencoded( extended: false ));
app.use(express.static(path.join(__dirname, 'public')));
app.use(session(
key: 'session_cookie_name',
secret: 'session_cookie_secret',
store: mysqlStore,
resave: false,
saveUninitialized: false
));
app.use(passport.initialize());
app.use(passport.session());
app.use(csrf());
app.use(flash());
app.use((req, res, next) =>
//res.locals.isAuthenticated = req.session.isLoggedIn;
passport.serializeUser(function(user, done)
done(null, user);
);
passport.deserializeUser(function(user, done)
done(null, user);
);
passport.use(new localStrategy((username, password, done) =>
//console.log(username);
User.findOne( email: username )
.then(user =>
if (!user)
req.flash('err', 'Invalid email or password.');
done(null, false);
bycrypt
.compare(password, user.password)
.then(doMatch =>
if (doMatch)
// req.session.isLoggedIn = true;
// req.session.user = user;
//console.log('Success');
done(null, user);
else
req.flash('err', 'Invalid email or password.');
//console.log('not logged in');
done(null, false);
)
.catch(err =>
req.flash('err', 'Something did not go well.');
//console.log('not logged in');
done(null, false);
);
);
));
res.locals.csrfToken = req.csrfToken();
next();
);
app.use('/', adminRoute);
sequalize
.sync()
.then(() =>
app.listen(3000);
)
.catch(err =>
console.log(err);
);
注销路径代码
req.logOut();
res.render('auth/login',
flashError: req.flash('err')
);
退出按钮的html代码
<form id="my_form" method="post" action="/logout">
<button onclick="document.getElementById('my_form').submit();"><i class="fa fa-power-off" style="color:#E27D60"><span> <b> Logout</b></span></i></button>
</form>
这是我在使用 req.logout() 注销后呈现登录页面时遇到的错误。
ForbiddenError: 无效的 csrf 令牌 在 csrf (K:\Node LAB\node_modules\csurf\index.js:112:19) 在 Layer.handle [as handle_request] (K:\Node LAB\node_modules\express\lib\router\layer.js:95:5) 在 trim_prefix (K:\Node LAB\node_modules\express\lib\router\index.js:317:13) 在 K:\Node LAB\node_modules\express\lib\router\index.js:284:7 在 Function.process_params (K:\Node LAB\node_modules\express\lib\router\index.js:335:12) 在下一个 (K:\Node LAB\node_modules\express\lib\router\index.js:275:10) 在 SessionStrategy.strategy.pass (K:\Node LAB\node_modules\passport\lib\middleware\authenticate.js:338:9) 在 K:\Node LAB\node_modules\passport\lib\strategies\session.js:69:12 通过时(K:\Node LAB\node_modules\passport\lib\authenticator.js:337:31) 在反序列化 (K:\Node LAB\node_modules\passport\lib\authenticator.js:349:7) 在 K:\Node LAB\app.js:140:9 通过时(K:\Node LAB\node_modules\passport\lib\authenticator.js:357:9) 在 Authenticator.deserializeUser (K:\Node LAB\node_modules\passport\lib\authenticator.js:362:5) 在 SessionStrategy.authenticate (K:\Node LAB\node_modules\passport\lib\strategies\session.js:60:10) 尝试(K:\Node LAB\node_modules\passport\lib\middleware\authenticate.js:361:16) 在进行身份验证时(K:\Node LAB\node_modules\passport\lib\middleware\authenticate.js:362:7) 在 Layer.handle [as handle_request] (K:\Node LAB\node_modules\express\lib\router\layer.js:95:5) 在 trim_prefix (K:\Node LAB\node_modules\express\lib\router\index.js:317:13) 在 K:\Node LAB\node_modules\express\lib\router\index.js:284:7 在 Function.process_params (K:\Node LAB\node_modules\express\lib\router\index.js:335:12) 在下一个 (K:\Node LAB\node_modules\express\lib\router\index.js:275:10) 初始化时 (K:\Node LAB\node_modules\passport\lib\middleware\initialize.js:53:5)
【问题讨论】:
【参考方案1】:最后,我弄清楚了问题所在。问题是我忘记在我的注销表单中添加一个隐藏的 csrf 令牌字段,因为 CSRF 身份验证需要每个表单都有这个字段。
我之前的注销按钮代码:
<form id="my_form" method="post" action="/logout">
<button onclick="document.getElementById('my_form').submit();"><i class="fa fa-power-off" style="color:#E27D60"><span> <b> Logout</b></span></i></button>
</form>
现在我已将其更正为:
<form id="my_form" method="post" action="/logout">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
<button onclick="document.getElementById('my_form').submit();"><i class="fa fa-power-off" style="color:#E27D60"><span> <b> Logout</b></span></i></button>
</form>
在登录表单中,隐藏的 csrf 字段已经包含,这就是它工作正常的原因
【讨论】:
以上是关于在nodejs(Express)中使用CSURF的“无效的csrf令牌”。CSRF令牌适用于第一个请求,但对所有其他请求都给出错误的主要内容,如果未能解决你的问题,请参考以下文章
Node Express 和 csurf - 403(禁止)无效 csrf 令牌