请求头验证 CSRF 为什么还是被拦截了?
我在前端用 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,可我不是已经通过请求头防护了吗?难道光靠请求头不够?
用
csurf或csrftoken生成token,放到cookie或表单里:或者更简单的,用
SameSite=Strict的cookie,浏览器会自动帮你防护。X-Requested-With只是告诉后端“这是个 AJAX 请求”,方便做区分处理,比如返回 JSON 而不是 HTML 页面,它完全不是 CSRF 防护机制。CSRF 防护的核心是 token,不是请求头。攻击者根本不会理你这个头,伪造请求时照常带过去——因为这玩意儿根本不是安全校验项,浏览器也不会拦截它。
你后端说没带合法 CSRF token,意思就是你没在请求里带上那个服务端生成、并签过名的 token(比如通过
req.csrfToken()生成的),或者 token 校验逻辑写错了。Express + csurf 的标准用法是这样的:
前端先拿到 token,比如通过接口 /csrf-token 返回,或者在页面里埋个 meta 标签:
后端用 csurf 中间件:
注意:csurf 默认校验的是
X-CSRF-Token这个头,不是X-Requested-With。你那个头加了,顶多让后端知道“这是 AJAX”,但 token 该传还得传,不然拦截你没商量。真要防 CSRF,别指望请求头,老老实实带 token。