使用csurf时遇到的Nodejs问题

使用csurf时遇到的Nodejs问题

在使用csurf时,正常的表单都没有问题,但是如果是上传表单就会403,网上都搜过都没找到解决方案。 有同学遇到类似问题吗,或者有没有其他替代方案?

4 回复

使用csurf时遇到的Nodejs问题

在使用csurf库时,通常情况下普通的表单提交是没有问题的,但是一旦涉及到文件上传的表单(例如使用multer处理文件上传),就可能会遇到403错误。这种错误通常是由于CSRF令牌验证失败导致的。

问题分析

当处理文件上传时,表单的enctype属性通常会被设置为multipart/form-data。在这种情况下,csurf可能无法正确读取请求中的CSRF令牌,从而导致验证失败。

解决方案

要解决这个问题,我们需要确保在处理文件上传时正确地传递和验证CSRF令牌。一种常见的方法是将CSRF令牌存储在会话中,并在表单中通过隐藏字段传递给服务器。

以下是一个简单的示例,展示如何使用csurfmulter处理文件上传:

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');
});

关键点解释

  1. Session配置:首先,我们需要配置一个session中间件来保存用户的会话信息。
  2. Multer配置:使用multer来处理文件上传。
  3. CSRF保护:使用csurf中间件来添加CSRF保护。这里我们使用了cookie: true选项,使得CSRF令牌可以通过cookie传递。
  4. 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 令牌需要被正确地插入到表单中,并且在文件上传时也必须包含在请求中。

以下是一些可能的解决方案:

  1. 确保 CSRF 令牌包含在上传表单中

    • 如果你在使用 multipart/form-data 进行文件上传,你需要确保 CSRF 令牌包含在该表单数据中。
  2. 手动处理 CSRF 令牌

    • 你可以手动将 CSRF 令牌添加到上传表单的数据中。

示例代码

安装依赖

首先,确保安装了 csurfmulter(用于文件上传):

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 保护,但这会降低安全性。

希望这些示例代码和建议能帮助你解决遇到的问题!

回到顶部