请求头验证 CSRF 为什么还是被拦截了?

智颖 阅读 26

我在前端用 fetch 发请求时加了自定义请求头 X-Requested-With: XMLHttpRequest,后端也配置了验证这个头,但 CSRF 攻击测试时还是被拦截了,这是为啥?

我试过在登录后的页面发起 POST 请求,代码是这样的:

fetch('/api/update', {
  method: 'POST',
  headers: {
    'X-Requested-With': 'XMLHttpRequest',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ data: 'test' })
})

但后端(用的 Express)说请求没带合法的 CSRF token,可我不是已经通过请求头防护了吗?难道光靠请求头不够?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
书生シ玉哲
光靠请求头确实不够。X-Requested-With 这个头可以被绕过(比如JSONP、表单提交),而且同源下攻击者直接执行JS就失效了。

csurfcsrftoken 生成token,放到cookie或表单里:

// 服务端
const csrf = require('csurf');
app.use(csrf({ cookie: true }));

// 前端,从cookie读取token
fetch('/api/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.cookie.match(/csrfToken=([^;]+)/)[1]
},
body: JSON.stringify({ data: 'test' })
})


或者更简单的,用 SameSite=Strict 的cookie,浏览器会自动帮你防护。
点赞
2026-03-12 12:04
♫丽苹
♫丽苹 Lv1
你搞混了两个概念:请求头 X-Requested-With 只是告诉后端“这是个 AJAX 请求”,方便做区分处理,比如返回 JSON 而不是 HTML 页面,它完全不是 CSRF 防护机制。

CSRF 防护的核心是 token,不是请求头。攻击者根本不会理你这个头,伪造请求时照常带过去——因为这玩意儿根本不是安全校验项,浏览器也不会拦截它。

你后端说没带合法 CSRF token,意思就是你没在请求里带上那个服务端生成、并签过名的 token(比如通过 req.csrfToken() 生成的),或者 token 校验逻辑写错了。

Express + csurf 的标准用法是这样的:

前端先拿到 token,比如通过接口 /csrf-token 返回,或者在页面里埋个 meta 标签:
fetch('/csrf-token')
.then(res => res.json())
.then(data => {
const token = data.csrfToken;

fetch('/api/update', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': token
},
body: JSON.stringify({ data: 'test' })
});
});


后端用 csurf 中间件:
const express = require('express');
const csrf = require('csurf');
const app = express();

app.use(csrf({ cookie: true })); // 或 { cookie: false } 用 session 存

app.use((req, res, next) => {
res.locals.csrfToken = req.csrfToken(); // 给模板用
next();
});

app.post('/api/update', (req, res) => {
// csurf 会自动校验 X-CSRF-Token 或 _csrf 字段
if (!req.csrfToken || req.csrfToken() !== req.headers['x-csrf-token']) {
return res.status(403).send('CSRF invalid');
}
// 你的逻辑
});


注意:csurf 默认校验的是 X-CSRF-Token 这个头,不是 X-Requested-With

你那个头加了,顶多让后端知道“这是 AJAX”,但 token 该传还得传,不然拦截你没商量。真要防 CSRF,别指望请求头,老老实实带 token。
点赞 7
2026-02-24 11:17