Fiber框架默认不启用CSRF防护,必须显式调用app.Use(csrf.New())注册中间件,且须在路由定义前完成;若漏配或挂载顺序错误,防护即失效。

Fiber框架默认不启用CSRF防护,必须显式配置中间件才能生效;漏掉 csrf.New() 或未正确挂载到路由,等于没防。
如何启用Fiber的CSRF中间件
CSRF防护不是开箱即用的功能,需手动引入并注册中间件。Fiber 2.40+ 版本中,csrf.New() 是唯一入口,它返回一个标准中间件函数。
- 必须在初始化
app := fiber.New()后立即调用app.Use(csrf.New()),否则后续路由无法被保护 - 若只对部分路由启用(如仅
/api/transfer),需将中间件单独挂载:app.Post("/api/transfer", csrf.New(), handler),但注意:此时csrf.New()每次都会新建实例,会丢失共享的令牌池,应避免 - 不支持全局禁用某条路由的CSRF检查(比如跳过健康检查),只能靠自定义中间件提前
return nil绕过,但绕过逻辑必须写在csrf.New()之前
双提交Cookie模式下token怎么传递
默认模式不依赖 session 存储,token 存于内存 + Cookie,客户端需在请求头和 Cookie 中“双提交”同一值。这是最容易出错的环节。
- 服务端自动设置
Set-Cookie: csrf_token=xxx; HttpOnly=false; SameSite=Lax(注意:不能设HttpOnly=true,否则前端 JS 读不到) - 客户端必须从 Cookie 读取
csrf_token值,并通过X-Csrf-Token请求头回传(不是X-CSRF-Token,大小写敏感) - 表单提交时,若用
fetch或axios,需手动读 Cookie 并设 header:headers: { 'X-Csrf-Token': getCsrfToken() };纯 HTML 表单无法自动带 header,必须配合 JS 初始化 - 浏览器原生
提交不会发自定义 header,此时必须改用同步令牌模式(基于 session)或前端拦截后转为 fetch
同步令牌模式(基于 session)怎么配
当应用已使用 session.New() 且希望 token 与用户会话强绑定时,需显式传入存储器,否则仍走默认的内存双提交模式。
- 必须先创建 session 存储器(如
store := session.New()),再传给csrf.New(csrf.Config{SessionStore: store}) - 此时 token 不再通过 Cookie 自动下发,而是由开发者在渲染页面时,从
c.Locals("csrf_token")取出,嵌入表单隐藏字段: - POST 请求体中必须含
csrf_token字段(表单编码或 JSON 都可),中间件会自动从 body、query 或 header(X-Csrf-Token)任一位置提取比对 - 注意:若同时存在 Cookie 和 body 中的 token,中间件优先用 body,但两者值必须一致,否则拒绝
常见错误现象和调试要点
403 Forbidden 却没提示原因?token 总是 mismatch?大概率卡在这几个点上。
-
csrf.New()被挂载在app.Static()之后 → 静态资源也被校验,导致 JS/CSS 加载失败,应确保中间件在所有Use()中最早注册 - 前端读 Cookie 时用了
document.cookie但未做split('; ')解析,或正则写错,拿到的是整个字符串而非 token 值 - 开发环境启用了代理(如 Vite 的
proxy),请求 Host 变成localhost:3000,但 Cookie 的Domain是example.com→ token 无法发送,需配置SameSite=None; Secure并确保 HTTPS - 用
curl -v测试时忘了加-b和-H "X-Csrf-Token: xxx",直接拿 403 当 bug,其实只是测试姿势不对
最易被忽略的是:CSRF 中间件对 OPTIONS 预检请求不做校验,但若前端跨域 POST 且带自定义 header(如 X-Csrf-Token),浏览器会先发 OPTIONS,而 Fiber 默认不处理该方法 —— 必须显式注册空的 app.Options("*", func(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusNoContent) }),否则预检失败,后续请求根本发不出。











