echo-jwt/v4 默认仅校验签名和时间字段,不防 alg:none、空字节攻击、jti 黑名单失效及 Nginx/CDN 头篡改,需手动增强校验逻辑。

为什么不能只靠 echo-jwt/v4 拦截伪造 JWT
echo-jwt/v4 默认只校验签名、exp/nbf/iat 时间字段,它不查 Redis、不验 jti、不拒绝 alg: none——也就是说,一个被泄露、被篡改、甚至被降级为无签名的 token,只要时间没过期,它就放行。伪造请求往往就卡在这个“合法但不可信”的缝隙里。
如何在中间件中提前拦截 alg: none 和空字节攻击
伪造者常把 Header.alg 改成 "none" 绕过签名验证,或在 payload 里塞 \x00 触发底层解析异常。这些必须在 echo-jwt 解析前挡住:
- 在
echo-jwt.Config.KeyFunc中显式检查:token.Header["alg"] == "none",直接返回nil, errors.New("alg none not allowed") - 用
io.LimitReader(c.Request().Body, 1024)读取原始请求体前 1KB,正则匹配\x00-\x08\x0B\x0C\x0E-\x1F等控制字符(注意:不是字符串解码后,是原始字节) - 若匹配到,立即
c.String(400, "")并return,不调next(c)
怎么让 echo-jwt 正确抛出 TokenExpired 错误
很多人发现过期 token 没被拦住,是因为 jwt.ParseWithClaims 默认不强制校验时间——它只在你主动调 token.Claims.VerifyExpiresAt(time.Now().Unix(), true) 时才报错。正确做法是:
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 在
echo-jwt.Config.ErrorHandler中判断err类型:errors.Is(err, jwt.ErrTokenExpired)或strings.Contains(err.Error(), "token is expired") - 别依赖
err == jwt.ErrTokenExpired,Go 的 jwt 库错误包装后类型会变 - 确保签发时
exp是秒级int64,不是毫秒;否则解析后立刻判定过期
伪造请求常绕过黑名单?因为 jti 没设或没对齐 TTL
黑名单机制失效,90% 出在 jti 字段和 Redis TTL 不一致:
- 签发时必须写
claims["jti"] = uuid.NewString(),不能用时间戳或用户 ID 替代 - Redis key 设为
revoked:{jti},TTL 必须等于 token 的exp - iat(比如 15 分钟),不能硬写time.Hour - 黑名单中间件必须放在
echo-jwt之后,且从c.Get("user")取已解析的*jwt.Token,别自己再 parse - 如果
jti为空,fallback 到token.Raw的 SHA256 做键(但性能差,仅应急)
真实部署中最容易被忽略的是:Nginx 或 CDN 可能重写了 Authorization 头,或者把 Bearer 前缀截掉。务必在中间件开头加一行日志:log.Printf("Auth header: %q", c.Request().Header.Get("Authorization")),确认拿到的是原始值。

















