Gin 默认不内置 CSRF 防护,因其遵循“最小内建、最大可控”设计哲学;CSRF 防护需结合会话管理、Token 生成校验及前端配合,且仅适用于依赖 Cookie 凭证的场景。

Gin 本身不内置 CSRF 防护中间件,必须手动集成或自行实现;直接依赖 Cookie + 表单提交的场景下,不加防护等于裸奔。
为什么 Gin 默认不防 CSRF
Gin 的设计哲学是“最小内建、最大可控”,它把安全决策权留给开发者。CSRF 防护需要结合会话管理、Token 生成/校验、前端配合等多个环节,而 Gin 并不强制绑定 session 或模板引擎——比如你用 JWT 做鉴权、前端用 React 管理状态、接口全走 JSON POST,那传统 Cookie-based CSRF 防护就可能不适用。
常见误判是以为「用了 gin-contrib/sessions 就自动带 CSRF」——其实它只管存 Session,Token 的签发、注入、比对全得自己写。
- CSRF 防护前提是:敏感操作依赖浏览器自动携带的凭证(如
session_idCookie) - 若你已切换到 JWT +
Authorization: Bearer xxx,且前端严格不存 Token 到 Cookie,则 CSRF 风险天然降低(但需防 XSS 泄露 Token) - 若仍用 Cookie 存 session,就必须补 Token 校验,否则
POST /transfer?to=attacker&amount=10000这类请求可被恶意页面一键触发
双重提交 Cookie 是 Gin 最轻量可靠的方案
不需要服务端存储 Token,也不依赖复杂 session 后端,适合微服务间松耦合部署。核心逻辑是:服务端 Set-Cookie 一个随机值(如 XSRF-TOKEN),前端在请求头(如 X-XSRF-TOKEN)或表单字段中回传相同值,服务端比对即可。
实操要点:
- 生成 Token 用
crypto/rand.Read(),长度至少 32 字节,别用时间戳或自增 ID - Set-Cookie 时必须设
HttpOnly=false(否则 JS 读不到),但要加SameSite=Lax和Secure(仅 HTTPS) - 校验中间件里,优先从
X-XSRF-TOKEN请求头取值;没 header 再 fallback 到表单字段_csrf;两者都无则拒绝 - GET、HEAD、OPTIONS 请求跳过校验(CSRF 只影响状态变更操作)
示例中间件片段:
func CSRFMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method == "GET" || c.Request.Method == "HEAD" || c.Request.Method == "OPTIONS" {
c.Next()
return
}
cookie, err := c.Request.Cookie("XSRF-TOKEN")
if err != nil {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "missing csrf token"})
return
}
headerToken := c.GetHeader("X-XSRF-TOKEN")
if headerToken != cookie.Value {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "invalid csrf token"})
return
}
c.Next()
}
}
不要在微服务网关层统一做 CSRF 校验
CSRF 是应用层协议级防护,不是传输层问题。如果你在 API 网关(如 Kong、Traefik)上试图统一拦截并验证 Token,会遇到三个硬伤:
- 网关通常不解析请求体(如 JSON POST),无法从 body 中提取
_csrf字段 - 网关无法安全生成和下发
XSRF-TOKENCookie(缺少应用上下文,比如用户 session 绑定) - 下游微服务若各自维护独立 session,Token 不互通,网关校验失去意义
正确做法是:每个需要防护的业务服务(如 user-service、order-service)单独挂载 CSRF 中间件,并确保其 session 存储(Redis/DB)与 Token 生成逻辑在同一进程或可信网络内。
前端配合最容易漏掉的两个点
后端再严,前端一错全白搭。这两个细节线上事故率极高:
- axios 默认不带 Cookie,
withCredentials: true必须显式开启,否则浏览器根本不会发送XSRF-TOKENCookie - fetch API 的
credentials: "include"必须设置,且响应头必须返回Access-Control-Allow-Credentials: true,否则浏览器静默丢弃 Cookie
另外,前端拿到 XSRF-TOKEN 后,别用 document.cookie 手动拼接——现代框架(React/Vue)应通过 axios.defaults.headers.common['X-XSRF-TOKEN'] = token 全局注入,避免遗漏请求。
真正难的是边界判断:比如一个微服务既提供 HTML 页面(含表单),又暴露 JSON API,那 CSRF 中间件必须精准区分路由前缀(如 /admin/* 挂,/api/* 不挂),而不是粗暴全局启用——否则 API 调用方(其他服务或 CLI 工具)会因缺 Token 直接失败。


















