jwt中间件必须自定义时间校验(允许±30秒偏差)和kid路由,签名验签需防body重复读、路径/参数归一化,logger与recovery中间件须脱敏日志、禁写panic响应,敏感配置需运行时校验与构建期隔离。

API 安全不是加个 jwt 或开个 HTTPS 就完事,而是要分层卡住「身份可信」「请求未篡改」「调用不越权」「流量不压垮」四个关键点。漏掉任一环,都可能被绕过。
JWT 中间件必须自定义时间校验和 kid 路由
用 github.com/golang-jwt/jwt/v5 时,默认 ParseWithClaims 会严格校验 exp 和 nbf,但生产环境服务器与客户端时钟不同步很常见——差 2 秒就拒签,用户直接报错 401。
- 必须显式传入
jwt.WithValidator替换默认校验器,允许 ±30 秒偏差(abs(now.UnixMilli() - exp) ) - 密钥轮换时,
keyFunc不能只返回一个公钥;要先从token.Header["kid"]取值,再查map[string]any返回对应密钥 - 如果 header 没
kid,keyFunc必须返回nil, errors.New("missing kid"),不能panic,否则recovery中间件会失效
签名验签中间件要防 body 重复读 + 路径/参数归一化
签名原文拼接错一点,服务端重算的签名就跟客户端对不上。常见坑是直接用 r.URL.Path 或 r.FormValue() 构造原文——它们已被自动 decode 或排序打乱。
- 路径用
r.URL.EscapedPath()(保留原始编码,如%2F不变) - query 参数从
r.URL.RawQuery解析,再按字典序排序键名、URL decode 值后拼接 -
body只能读一次:用io.TeeReader(r.Body, buf)或提前io.ReadAll到bytes.Buffer,再分别供验签和业务 handler 使用 - 验签前必须调用
r.Body = io.NopCloser(buf),否则后续 handler 读不到body
Logger 和 Recovery 中间件配置不当会反向泄露敏感信息
很多团队开了 fiberRecover.Config.EnableStackTrace = true 就以为“有堆栈了”,但没关响应写入,panic 信息会直接混进 JSON 响应体里返回给客户端。
-
Logger中间件必须补全RequestID、User-Agent、BodyHash(SHA256(body)),否则审计时无法定位异常请求源头 - 补
BodyHash前得先调ctx.Request().DisableBodyConsumption(),否则业务 handler 读不到body -
Recovery的StackTraceHandler函数里,只能调l.Error()记日志,绝不能调w.Write()或ctx.Send();且要在 handler 结束后显式执行ctx.Response().Reset()清空已写入的响应缓冲区
敏感配置必须 runtime 校验 + 构建期隔离
硬编码密钥、用 os.Getenv("SECRET") || "dev-key" 当默认值、在日志里打完整 config 结构——这些都会让安全防护形同虚设。
- 启动时强制校验必要环境变量是否非空,比如
if os.Getenv("JWT_PUBLIC_KEY_PATH") == "" { log.Fatal("JWT_PUBLIC_KEY_PATH required") } - 密钥文件路径必须存在且可读,用
os.Stat和os.Open预检,失败直接 panic - 构建阶段禁用 dev 默认值:CI 中用
go build -ldflags="-X main.env=prod"控制行为,避免本地测试逻辑污染线上 - 所有
log.Printf或fmt.Printf输出配置前,先做字段脱敏(如secret: "***")
真正落地时,光有中间件骨架不够,关键在配置顺序、参数取舍和错误处理的边界——比如 jwt 中间件必须放在 logger 之后、recovery 之前;body 读取和哈希必须在任何中间件调用 ctx.Body() 前完成;kid 缺失时返回 error 而非 panic 这种细节,才是压垮安全防线的最后一根稻草。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











