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

长孙子赫 阅读 3

我在前端用 fetch 发请求时加了自定义请求头 X-Requested-With: XMLHttpRequest,后端也配置了校验这个头,但还是被 CSRF 防护拦住了,到底是哪出问题了?

我试过在 Axios 里也加了同样的头,本地开发环境没问题,一上测试环境就 403。后端同事说他们只认这个头,但浏览器发 OPTIONS 预检之后实际请求好像没带上?

fetch('/api/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest'
  },
  body: JSON.stringify({ data: 'test' })
})
我来解答 赞 0 收藏
二维码
手机扫码查看
1 条解答
巧玲🍀
问题找到了,就是后端对OPTIONS请求也做了CSRF校验。

浏览器发非简单请求(带自定义头)之前会先发OPTIONS预检,这个预检请求可不会带你的X-Requested-With头。后端如果对OPTIONS也拦截,那就直接跪了。

解决方案很简单:后端在CSRF验证那里加个判断,把OPTIONS请求跳过去。

PHP的话大概长这样:

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
// 预检请求直接放行
http_response_code(200);
exit;
}


或者用中间件的方式,在CSRF验证逻辑的最前面判断请求方法。

还有个更根本的思路:现在主流做法其实是用SameSite Cookie + CSRF Token,单纯靠请求头判断这种方式本身就有漏洞(因为浏览器正常请求确实会带这个头,但攻击者的恶意请求也可以构造这个头)。如果后端还在用这种方案,建议考虑升级一下防护策略。
点赞
2026-03-13 17:04