You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NodeJS带认证场景下文件上传出现csrf token无效问题的解决方案咨询

解决multipart/form-data表单上传时CSRF Token无效的问题

我之前也碰到过一模一样的问题,用multipart/form-data提交文件时总是触发CSRF验证失败,折腾了好一会儿才找到几个靠谱的解决办法,分享给你:

1. 调整中间件顺序,确保multer在CSRF中间件之前执行

很多时候问题出在中间件的执行顺序上。如果你用的是Express+csurf+multer的组合,一定要让multer先处理请求,这样CSRF中间件才能从请求体里读取到_csrf字段。

举个例子,正确的路由配置应该是这样:

const express = require('express');
const multer = require('multer');
const csurf = require('csurf');
const cookieParser = require('cookie-parser');

const app = express();
app.use(cookieParser());

// 配置multer处理文件上传,这里用磁盘存储为例
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './uploads/');
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + '-' + file.originalname);
  }
});
const upload = multer({ storage: storage });

// 初始化CSRF中间件
const csrfProtection = csurf({ cookie: true });

// 路由:先让multer处理文件,再做CSRF验证
app.post('/createtest/question', upload.single('file'), csrfProtection, (req, res) => {
  // 这里可以访问req.file拿到上传的文件,req.body拿到_csrf等字段
  res.send('文件上传成功');
});

如果之前你把CSRF中间件放在multer前面,CSRF中间件会先执行,这时候请求体还没被解析,自然找不到_csrf字段,就会报错。

2. 改用请求头传递CSRF Token

如果表单里的_csrf字段总是无法被正确识别,可以试试把Token放在请求头里。这种方式对multipart/form-data请求兼容性更好:

后端配置

先修改CSRF中间件,让它把Token存在Cookie里:

const csrfProtection = csurf({ 
  cookie: { 
    httpOnly: false, // 允许前端JS读取Cookie
    sameSite: 'strict' 
  } 
});

// 在渲染表单的路由里,把Token传给模板(其实这一步可以省略,前端直接从Cookie读)
app.get('/upload', csrfProtection, (req, res) => {
  res.render('upload', { csrfToken: req.csrfToken() });
});

前端修改

去掉表单里的隐藏_csrf字段,用JavaScript监听表单提交,通过请求头传递Token:

<form id="fileUploadForm" action="/createtest/question" method="post" enctype="multipart/form-data">
  <input type="file" name="file">
  <button type="submit">上传文件</button>
</form>

<script>
// 从Cookie中获取CSRF Token的工具函数
function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}

document.getElementById('fileUploadForm').addEventListener('submit', function(e) {
  e.preventDefault(); // 阻止默认表单提交

  const csrfToken = getCookie('XSRF-TOKEN'); // 注意Cookie名称,默认是XSRF-TOKEN
  const formData = new FormData(this);

  // 用fetch提交请求
  fetch(this.action, {
    method: 'POST',
    headers: {
      'X-CSRF-Token': csrfToken // 在请求头里带上Token
    },
    body: formData
  })
  .then(response => response.text())
  .then(data => {
    console.log(data);
    // 处理上传成功后的逻辑
  })
  .catch(error => {
    console.error('上传失败:', error);
  });
});
</script>

这样做的好处是,请求头里的Token不会被multipart的解析逻辑干扰,CSRF中间件能直接读取到。

3. 检查Token的渲染是否正确

有时候问题很简单,就是模板里的<%= csrfToken %>没有正确输出Token。你可以打开浏览器的开发者工具,查看页面源码,确认隐藏字段的value是不是一个有效的字符串,而不是undefined或者空值。如果是空的,那就要检查后端渲染模板时有没有正确传递csrfToken变量。

比如在Express的路由里,必须确保在渲染模板前先执行CSRF中间件:

app.get('/createtest', csrfProtection, (req, res) => {
  res.render('createtest', { csrfToken: req.csrfToken() });
});

内容的提问来源于stack exchange,提问作者Vishy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 21:22:36