React表单提交如何防止CSRF攻击?隐藏字段没生效?

书圻 ☘︎ 阅读 13

在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就会被拦截,但前端这样写哪里有问题?

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
爱学习的玉戈
你遇到的问题主要是因为浏览器的同源策略和 fetch API 的默认行为导致的。常见的解决方案是确保 fetch 请求正确携带 Cookie,这需要在 fetch 选项里显式设置 credentials: 'include'。默认情况下,fetch 不会自动带上 Cookie,而后端又依赖 Cookie 里的 CSRF 令牌来验证请求。

你的代码需要调整的地方不多,重点是在 fetch 请求中加上这个配置。另外,隐藏字段其实在这里不是必须的,因为后端更关注的是 Cookie 和请求体里的 CSRF 令牌是否匹配。以下是修改后的代码:

function CancelOrderForm() {
const [csrfToken, setCsrfToken] = useState('');

useEffect(() => {
fetch('/api/csrf-token', { credentials: 'include' })
.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
}),
credentials: 'include' // 确保带上 Cookie
});
};

return (
<form onSubmit={handleSubmit}>
<input type="hidden" name="_csrf" value={csrfToken} />
<button type="submit">取消订单</button>
</form>
);
}


另外需要注意的是,如果你的前端和后端不在同一个域名下,比如前端运行在 localhost:3000 而后端在 api.example.com,还需要确保后端正确设置了 CORS 策略,允许前端域名访问,并且支持 credentials。后端的响应头应该包含类似这样的配置:

Access-Control-Allow-Origin: https://your-frontend-domain.com
Access-Control-Allow-Credentials: true


如果后端没有正确设置 CORS,浏览器会直接拦截跨域请求,连带 Cookie 都不会发送。你可以先用浏览器开发者工具检查网络请求,看看是不是跨域问题导致的。

最后吐槽一句,CSRF 这种东西每次调试都挺烦人的,尤其是前后端分离的项目,搞不好就会被安全机制拦住。希望这些调整能帮你解决问题。
点赞 1
2026-02-15 23:05