Gin 默认不带 CSRF 防护,因其作为极简框架,将会话、token 管理等交由第三方库处理,csrf 防护必须与会话机制耦合,故需手动集成如 gorilla/csrf 或 gin-contrib/csrf 等中间件。

为什么 Gin 默认不带 CSRF 防护?
Gin 本身是极简框架,gin.Engine 不内置 CSRF 中间件,也不自动注入或校验 token。这不是疏忽,而是设计取舍:CSRF 防护必须与会话机制耦合(比如依赖 session 存储 token),而 Gin 把会话、加密、token 管理都交由第三方库处理。直接用 gin.Default() 启动的服务,对 POST 表单或 JSON 请求完全不做 CSRF 检查——攻击者可伪造请求,只要 Cookie 有效就能通过认证。
gorilla/csrf 在 Gin 中的正确集成方式
gorilla/csrf 是最成熟的选择,但它不是为 Gin 原生设计的,强行套用 http.Handler 转换容易出错。关键点在于:中间件必须包裹路由,且需确保前置会话中间件已生效。
- 先引入会话支持,例如用
github.com/gin-contrib/sessions,并确保 session store 已初始化(如cookie.NewStore([]byte("secret"))) - CSRF 中间件必须在会话中间件之后注册,否则
csrf.Token()无法读取 session - 不要用
router.Use(csrf.Protect(...))全局启用——它会拦截所有请求(包括静态资源、健康检查),应只作用于敏感路由组 - 若前端是 SPA(如 React/Vue),需显式从响应头或 JSON body 中提取
X-CSRF-Token,并在后续请求 header 中携带;不能只靠表单隐藏字段
示例片段:
store := cookie.NewStore([]byte("session-secret"))
router.Use(sessions.Sessions("mysession", store))
// 仅保护 /api/admin 下的 POST/PUT/DELETE
adminGroup := router.Group("/api/admin")
adminGroup.Use(csrf.Protect(
[]byte("32-byte-long-key-here"),
csrf.Secure(false), // 开发环境可设 false;生产务必 true + HTTPS
csrf.HttpOnly(true),
csrf.SameSite(http.SameSiteLaxMode),
))
adminGroup.POST("/user/delete", deleteHandler)
SameSite 和 Secure 标志的实际影响
CSRF 防护不是“加个中间件就完事”,csrf.SameSite 和 csrf.Secure 参数直接决定浏览器是否发送 Cookie,进而影响 token 绑定有效性。
立即学习“go语言免费学习笔记(深入)”;
-
csrf.Secure(true)要求 Cookie 只在 HTTPS 下发送;本地开发用 HTTP 时必须设false,否则 token 无法写入 Cookie,导致csrf.Token()返回空 -
csrf.SameSite(http.SameSiteLaxMode)是平衡安全与可用性的默认选择:允许 GET 表单提交(如搜索),但阻止跨站 POST;若业务要求更严格(如银行转账),应改用http.SameSiteStrictMode - 若前端部署在不同域名(如
app.example.com+api.example.com),SameSite=Lax仍可能失效,此时需配合 CORS + 凭据 + token header 传递
CSRF Token 在 Gin 模板和 API 中的不同用法
模板渲染和纯 API 的 token 使用路径完全不同,混用会导致 403 错误。
- 模板中(
html/template):用{{.CSRF}}或{{.CsrfField}}(取决于中间件配置),本质是插入隐藏 input 字段 - API 场景(如 Axios/Fetch):必须从初始 HTML 或登录响应中获取
X-CSRF-Token响应头,并在后续请求 header 中带上X-CSRF-Token: xxx - 注意:
csrf.Token(r)在 handler 内调用时,依赖当前 request 是否已通过中间件解析 session;若跳过中间件直接调用,返回空字符串 - 不要手动拼接 token 到 URL 查询参数(如
?_csrf=xxx),这会泄露 token 到 referer 日志和服务器 access log
真正容易被忽略的是:CSRF token 的生命周期绑定 session,session 过期后 token 自动失效,但前端可能缓存旧 token 并反复重试——这时应返回 403 并提示用户刷新页面,而不是静默失败。


















