使用csurf时遇到的Nodejs问题
使用csurf时遇到的Nodejs问题
在使用csurf时,正常的表单都没有问题,但是如果是上传表单就会403,网上都搜过都没找到解决方案。 有同学遇到类似问题吗,或者有没有其他替代方案?
使用csurf时遇到的Nodejs问题
在使用csurf
库时,通常情况下普通的表单提交是没有问题的,但是一旦涉及到文件上传的表单(例如使用multer
处理文件上传),就可能会遇到403错误。这种错误通常是由于CSRF令牌验证失败导致的。
问题分析
当处理文件上传时,表单的enctype
属性通常会被设置为multipart/form-data
。在这种情况下,csurf
可能无法正确读取请求中的CSRF令牌,从而导致验证失败。
解决方案
要解决这个问题,我们需要确保在处理文件上传时正确地传递和验证CSRF令牌。一种常见的方法是将CSRF令牌存储在会话中,并在表单中通过隐藏字段传递给服务器。
以下是一个简单的示例,展示如何使用csurf
和multer
处理文件上传:
const express = require('express');
const session = require('express-session');
const csrf = require('csurf');
const multer = require('multer');
const app = express();
// 配置session
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: true
}));
// 配置multer用于文件上传
const upload = multer({ dest: 'uploads/' });
// 配置csurf
const csrfProtection = csrf({ cookie: true });
app.get('/form', csrfProtection, (req, res) => {
res.send(`
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>
`);
});
app.post('/upload', csrfProtection, upload.single('file'), (req, res) => {
console.log(req.file); // 文件信息
res.send('File uploaded successfully.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
关键点解释
- Session配置:首先,我们需要配置一个session中间件来保存用户的会话信息。
- Multer配置:使用
multer
来处理文件上传。 - CSRF保护:使用
csurf
中间件来添加CSRF保护。这里我们使用了cookie: true
选项,使得CSRF令牌可以通过cookie传递。 - CSRF Token传递:在表单中通过隐藏字段传递CSRF令牌,确保它能够被服务器正确读取并验证。
通过上述配置,可以确保在处理文件上传时,CSRF令牌能够正确传递和验证,避免403错误的发生。
你说的403是指 invalid csrf token 吗? 如果是,这表示表单提交的csrfToken和期望的csrfToken不匹配。
// check user-submitted value
if (!tokens.verify(secret, value(req))) {
var err = new Error('invalid csrf token');
err.status = 403;
next(err);
return;
}
Expressjs的csurf中间件缺省这样提取csrfToken:
function defaultValue(req) {
return (req.body && req.body._csrf) // POST _csrf字段
|| (req.query && req.query._csrf) // GET _csrf字段
|| (req.headers['x-csrf-token']) // 扩展的x-csrf-token或x-xsrf-token请求头
|| (req.headers['x-xsrf-token']);
}
比较怪异的是:即使表单的enctype设置为multipart/form-data, 也不会影响这些字段的提交。 如果还不能找到原因,估计可行的方法就是到node_modules/csurf/index.js中查看代码。
请问 最后怎么解决的啊
在使用 csurf
中遇到上传表单时出现 403 错误的问题,通常是由于 CSRF 令牌没有正确地包含在请求中导致的。CSRF 令牌需要被正确地插入到表单中,并且在文件上传时也必须包含在请求中。
以下是一些可能的解决方案:
-
确保 CSRF 令牌包含在上传表单中:
- 如果你在使用
multipart/form-data
进行文件上传,你需要确保 CSRF 令牌包含在该表单数据中。
- 如果你在使用
-
手动处理 CSRF 令牌:
- 你可以手动将 CSRF 令牌添加到上传表单的数据中。
示例代码
安装依赖
首先,确保安装了 csurf
和 multer
(用于文件上传):
npm install csurf multer
设置中间件
const express = require('express');
const csrf = require('csurf');
const multer = require('multer');
const app = express();
const upload = multer();
// 创建 CSRF 保护中间件
const csrfProtection = csrf({ cookie: true });
app.use(upload.array()); // 使用 multer 处理文件上传
app.use(express.urlencoded({ extended: true })); // 解析 URL 编码的表单数据
// 在路由之前应用 CSRF 保护
app.get('/upload', csrfProtection, (req, res) => {
res.send(`
<form action="/process" method="POST" enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<input type="file" name="image">
<button type="submit">Upload</button>
</form>
`);
});
app.post('/process', csrfProtection, upload.single('image'), (req, res) => {
// req.file 包含上传的文件信息
res.send('File uploaded successfully.');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
在这个例子中,我们在表单中添加了一个隐藏的 _csrf
字段,并在处理文件上传的 POST 请求中使用了 csrfProtection
中间件来验证 CSRF 令牌。
替代方案
如果你仍然遇到问题,可以考虑使用其他 CSRF 库,如 express-session-csrf
或者完全不使用 CSRF 保护,但这会降低安全性。
希望这些示例代码和建议能帮助你解决遇到的问题!