gin-csrf 是 Gin 生态主流轻量 CSRF 中间件,需严格按顺序集成:先注册 session 中间件,再调用 csrf.New() 并置于 router.Use() 中 session 之后,正确配置 session key、校验方法及 token 注入方式,同时确保 SameSite 和 Secure Cookie 等 HTTP 层设置完备。

gin-csrf 是目前 Gin 生态中主流、轻量且与 gin-contrib/sessions 兼容的 CSRF 防御中间件。它不依赖全局状态,直接基于会话生成/校验一次性令牌,适合大多数表单提交和 POST API 场景。但要注意:它不是开箱即用的“安全开关”,配置错一步就形同虚设。
如何正确集成 gin-csrf 中间件
关键不是加中间件,而是确保它运行在会话中间件之后、路由处理之前——顺序错了,session.Values 就是空的,令牌永远生成失败。
- 必须先注册
gin-contrib/sessions(如基于 cookie 或 redis 的 store),再调用csrf.New() -
csrf.New()返回的中间件要放在router.Use()中,且位置需在 session 中间件之后 - 若使用自定义 session key(非默认
session),需通过csrf.WithSessionKey("your_key")显式传入 - 默认只对
POST、PUT、DELETE等非幂等方法校验;如需保护 GET(不推荐),得手动设置csrf.WithMethods([]string{"GET", "POST"})
csrf.Token() 怎么安全地注入到 HTML 表单里
不能靠模板变量硬塞,也不能在 JS 里拼接字符串——XSS 漏洞会让攻击者直接窃取或伪造 token。
- 在 Gin handler 中调用
c.GetHeader("X-CSRF-Token")或从上下文取csrf.Token(c),然后通过c.HTML()的 data 传入模板 - 模板中用
{{.CSRFToken}}插入隐藏域: - 不要把 token 放在 URL query 或 body 的任意字段名里;
gin-csrf默认只检查csrf_token字段或X-CSRF-Tokenheader - 前端 AJAX 请求务必带上 header:
headers: { 'X-CSRF-Token': document.querySelector('input[name=csrf_token]').value }
为什么启用后仍被绕过?常见失效原因
最常踩的坑不是代码写错,而是 HTTP 层配置没跟上——CSRF 防御是前后端+浏览器三方协作的结果。
-
SameSiteCookie 缺失:如果 session cookie 没设SameSite=Lax或Strict,旧版浏览器或某些跨站场景下,token 校验可能成功但请求本身已被浏览器静默携带凭证 - HTTPS 缺失却用了
Secure标志:开发环境用 HTTP 时,若 session store 配置了secure: true,cookie 不会被发送,导致 session 为空 → token 无法生成 - 前端未同步刷新 token:每次成功提交后,
gin-csrf默认会重置 token(防止重放),但前端没重新拉取新值,下次提交必然 403 - 忽略静态资源路径:中间件默认对所有路径生效,若你把
/static/*排除在外,但又在静态 JS 里发起敏感请求,校验就被跳过了
要不要同时用 Referer 校验?
不建议单独依赖,更不建议用它替代 token——Referer 可被浏览器隐私策略屏蔽、代理清理,或被恶意页面伪造(尤其在非 HTTPS 下)。
-
gin-csrf本身不内置 Referer 检查;若真要加,得自己写中间件,在csrf之后拦截并比对r.Referer() - 仅当业务明确要求「只允许来自自身域名的请求」且能接受一定误拦率时,才可作为辅助手段
- 真正该优先投入精力的是:确保所有敏感接口走 POST/PUT/DELETE + token,禁用状态变更类 GET,并强制
SameSite+SecureCookie
CSRF 防御真正的复杂点不在 Go 代码怎么写,而在于你能否让每个环节——从 cookie 设置、token 生命周期、前端注入方式,到浏览器行为兼容性——全部咬合到位。漏掉任意一环,都可能让整个防护链条失效。











