React表单提交如何防止CSRF攻击?隐藏字段没生效?
在React项目里做订单取消功能,用隐藏字段传CSRF令牌,但提交时后端返回403错误。代码是这样写的:
function CancelOrderForm() {
const [csrfToken, setCsrfToken] = useState('');
useEffect(() => {
fetch('/api/csrf-token')
.then(res => res.json())
.then(data => setCsrfToken(data.token));
}, []);
const handleSubmit = (e) => {
e.preventDefault();
fetch('/orders/cancel', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId: '12345',
_csrf: csrfToken
})
});
};
return (
<form onSubmit={handleSubmit}>
<input type="hidden" name="_csrf" value={csrfToken} />
<button type="submit">取消订单</button>
</form>
);
}
后端要求同时携带Cookie里的CSRF令牌和表单里的隐藏字段,但请求头没有自动带Cookie。直接用Postman测试时如果少了Cookie里的token就会被拦截,但前端这样写哪里有问题?
credentials: 'include'。默认情况下,fetch 不会自动带上 Cookie,而后端又依赖 Cookie 里的 CSRF 令牌来验证请求。你的代码需要调整的地方不多,重点是在 fetch 请求中加上这个配置。另外,隐藏字段其实在这里不是必须的,因为后端更关注的是 Cookie 和请求体里的 CSRF 令牌是否匹配。以下是修改后的代码:
另外需要注意的是,如果你的前端和后端不在同一个域名下,比如前端运行在
localhost:3000而后端在api.example.com,还需要确保后端正确设置了 CORS 策略,允许前端域名访问,并且支持credentials。后端的响应头应该包含类似这样的配置:如果后端没有正确设置 CORS,浏览器会直接拦截跨域请求,连带 Cookie 都不会发送。你可以先用浏览器开发者工具检查网络请求,看看是不是跨域问题导致的。
最后吐槽一句,CSRF 这种东西每次调试都挺烦人的,尤其是前后端分离的项目,搞不好就会被安全机制拦住。希望这些调整能帮你解决问题。