必须使用github.com/golang-jwt/jwt/v5,因其修复cve-2020-26160等签名绕过漏洞,强制显式算法校验与密钥类型,移除signingmethodnone,而旧版jwt-go已归档且存在真实线上风险。

为什么用 github.com/golang-jwt/jwt/v5 而不是旧版 jwt-go
旧版 jwt-go(v3 及更早)在 2020 年被发现存在严重安全漏洞(CVE-2020-26160),允许攻击者绕过签名验证,伪造任意 alg 声明实现签名校验绕过。v5 是当前官方维护分支,修复了该问题,并重构了 API,强制显式指定签名方法和密钥类型。
- 旧版
Parse默认接受任意alg,不校验 header 中的算法是否与实际验签逻辑匹配 - v5 中
ParseWithClaims必须传入明确的KeyFunc,且内部会校验 headeralg是否与SigningMethod一致 - 如果你还在用
github.com/dgrijalva/jwt-go或github.com/golang-jwt/jwt/v4,请立即升级 —— v4 已停止维护,v5 才是当前唯一受支持版本
ParseWithClaims 的 KeyFunc 怎么写才安全
KeyFunc 不是简单返回密钥,而是要根据 token header 动态决定密钥来源,尤其在多算法或多租户场景下。硬编码 return []byte("secret") 会导致所有 token 共用同一密钥,无法做密钥轮换或算法隔离。
- 必须先从
*jwt.Token中提取Header["alg"],再据此选择对应密钥;否则 RS256 和 HS256 混用时会 panic 或验签失败 - 若只用 HS256,仍建议封装为函数,避免密钥泄露到日志或错误堆栈中(例如不要直接
fmt.Printf("%s", key)) - 生产环境密钥应从环境变量或密钥管理服务加载,而非写死在代码里:
os.Getenv("JWT_SECRET_KEY") - 示例 KeyFunc:
func(key *jwt.Token) (interface{}, error) { if _, ok := key.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", key.Header["alg"]) } return []byte(os.Getenv("JWT_SECRET_KEY")), nil }
跨域请求中 Authorization 头丢失的常见原因
前端发请求带了 Authorization: Bearer xxx,但 Go 后端中间件收不到,大概率不是 JWT 解析问题,而是 CORS 配置或浏览器拦截导致。
- Go 的
net/http默认不暴露Authorization头给前端 JavaScript,需显式设置Access-Control-Expose-Headers(虽然它不影响接收,只影响前端读取响应头) - 真正关键的是:必须在 CORS 中间件里加上
Access-Control-Allow-Headers: Authorization,否则浏览器会预检(OPTIONS)失败并静默丢弃请求 - 使用
gin-contrib/cors时,确保cors.Config{AllowHeaders: []string{"Authorization", "Content-Type"}}包含Authorization - 检查前端是否在 credentials 模式下发送请求(
withCredentials: true),此时后端必须设Access-Control-Allow-Origin为具体域名,不能用*
如何防止已签发的 JWT 在过期前被滥用
JWT 本身无状态,一旦签发就无法主动废止 —— 这是设计特性,不是 bug。但生产环境必须应对令牌泄露、用户登出、密码修改等场景。
- 最轻量做法:维护一个 Redis 黑名单(
blacklist:{jti}),在解析成功后额外查一次;jti字段需在签发时生成 UUID 并存入 payload - 避免全量存储 token 字符串(太占内存),只存
jti+exp,利用 Redis 过期自动清理:SET blacklist:abc123 "true" EX 7200 - 登出接口只需删掉对应
jti,无需等待 token 自然过期 - 注意:黑名单校验应在
ParseWithClaims成功之后、业务逻辑之前执行,否则可能漏掉已失效但未过期的 token
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











