英文:
Csurf Forbidden Error: invalid csrfToken code: 'EBADCSRFTOKEN' in nodejs
问题
在我的博客项目中,CSRF 在一些 POST 路由上正常工作,比如登录、注册、注销、更新帐户信息等,但在管理员路由中,当我尝试创建/更新帖子或类别时失败并抛出禁止错误。我尝试了许多其他问题中提到的解决方案,但都没有解决我的问题。
require('dotenv').config();
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const flash = require('connect-flash');
const csrf = require('csurf');
const errorController = require('./controllers/error');
const uri = process.env.URI;
const app = express();
const csrfProtection = csrf();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(
session({
secret: 'my secrets',
saveUninitialized: false,
resave: false,
store: MongoStore.create({
mongoUrl: uri,
autoRemove: 'native',
ttl: 7200, //2 hours
collectionName: 'sessions',
}),
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.name = undefined; //
res.locals.level = 0; //
if (req.session.user) { //
res.locals.name = req.session.user.name; //those line for render nav bar in views
res.locals.level = req.session.user.level;//
} //
res.locals.csrfToken = req.csrfToken();
next();
});
// routes
const authRoutes = require('./routes/auth');
const pageRoutes = require('./routes/page');
const adminRoutes = require('./routes/admin');
app.use(pageRoutes); //
app.use('/auth', authRoutes); //everything works fine
app.use('/admin', adminRoutes); // errors
// error pages
app.use(errorController.get404);
app.use((error, req, res, next) => {
console.log(error);
res.status(500).render('errors/500', {
pageTitle: '500',
error: error,
});
});
mongoose
.connect(uri)
.then(result => {
app.listen(3000);
})
.catch(error => console.log(error));
我在每个 POST 表单中都添加了以下输入:
<input type="hidden" name="_csrf" value="<%= csrfToken%>" />
当我将错误日志记录时:
ForbiddenError: invalid csrf token
at csrf (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\csurf\index.js:112:19)
at Layer.handle [as handle_request] (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:328:13)
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:286:9
at Function.process_params (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:346:12)
at next (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:280:10)
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express-session\index.js:506:7
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\connect-mongo\build\main\lib\MongoStore.js:221:17
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'EBADCSRFTOKEN'
}
感谢每一个答案!因为我可以从这里的每个人那里学到一些东西。
英文:
In my blog project, csrf works fine on some post routes like login, register, logout, update account information,... but in the admin routes, when I tried to create/update a post or a category - it failed and threw the forbidden error. I tried many solutions from other questions but nothing worked for me.
require('dotenv').config();
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoStore = require('connect-mongo');
const flash = require('connect-flash');
const csrf = require('csurf');
const errorController = require('./controllers/error');
const uri = process.env.URI;
const app = express();
const csrfProtection = csrf();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(
session({
secret: 'my secrets',
saveUninitialized: false,
resave: false,
store: MongoStore.create({
mongoUrl: uri,
autoRemove: 'native',
ttl: 7200, //2 hours
collectionName: 'sessions',
}),
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.name = undefined; //
res.locals.level = 0; //
if (req.session.user) { //
res.locals.name = req.session.user.name; //those line for render nav bar in views
res.locals.level = req.session.user.level;//
} //
res.locals.csrfToken = req.csrfToken();
next();
});
// routes
const authRoutes = require('./routes/auth');
const pageRoutes = require('./routes/page');
const adminRoutes = require('./routes/admin');
app.use(pageRoutes); //
app.use('/auth', authRoutes); //everything works fine
app.use('/admin', adminRoutes); // errors
// error pages
app.use(errorController.get404);
app.use((error, req, res, next) => {
console.log(error);
res.status(500).render('errors/500', {
pageTitle: '500',
error: error,
});
});
mongoose
.connect(uri)
.then(result => {
app.listen(3000);
})
.catch(error => console.log(error));
And I have put this input in every post form:
<input type="hidden" name="_csrf" value="<%= csrfToken%>" />
The error when I logged it out:
ForbiddenError: invalid csrf token
at csrf (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\csurf\index.js:112:19)
at Layer.handle [as handle_request] (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:328:13)
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:286:9
at Function.process_params (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:346:12)
at next (D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express\lib\router\index.js:280:10)
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\express-session\index.js:506:7
at D:\Tai lieu hoc tap\Code\Personal Projects\Blog\node_modules\connect-mongo\build\main\lib\MongoStore.js:221:17
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
code: 'EBADCSRFTOKEN'
}
Thanks for every answer! Because I can learn something from everyone here.
答案1
得分: 0
问题出在表单标签中的enctype属性。在身份验证路由中只更新文本,因此我使用默认的enctype(application/x-www-form-urlencoded
),但在更新帖子或类别时可能会更新新图像,所以我使用了带有multer的多部分enctype。
只需要在表单操作中添加一个查询,名称为_csrf
,值为csrfToken
。不再有错误。
之前:
<form action="/admin/update-post" method="POST" enctype="multipart/form-data">
之后:
<form action="/admin/update-post?_csrf=<%= csrfToken%>" method="POST" enctype="multipart/form-data">
英文:
The problem here came from enctype in the form tag. While updating in auth routes only about texts so I use default enctype (application/x-www-form-urlencoded
), but updating a post or category may update a new image so I use multipart enctype with multer.
Just need to add a query in form action with the name = _csrf, value = csrfToken. No more error.
Before:
<form action="/admin/update-post" method="POST" enctype="multipart/form-data">
After:
<form action="/admin/update-post?_csrf=<%= csrfToken%>" method="POST" enctype="multipart/form-data">
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论