echo-jwt/v4默认仅校验签名,必须显式配置keyfunc拒绝alg:none、验证算法类型,并设置validtimefunc校验exp/nbf/iat,否则存在绕过、过期token有效等严重风险。

echo-jwt/v4 默认只校验签名,但必须显式配置 KeyFunc 和时间校验逻辑,否则会跳过关键验证项,导致 alg:none 绕过、过期 token 不拒、时间戳错乱等严重问题。
KeyFunc 里必须拒绝 alg:none 并校验签名算法
很多人只传一个固定密钥,却没在 KeyFunc 中检查 token.Header["alg"],结果攻击者可构造 alg:none 的 JWT 绕过签名验证。
- 必须在
KeyFunc中判断:if token.Header["alg"] == "none" { return nil, errors.New("alg none not allowed") } - 同时确认签名方法类型,例如只接受 HMAC:
_, ok := token.Method.(*jwt.SigningMethodHMAC) - 返回密钥前务必校验
token.Method是否符合预期,否则jwt.ParseWithClaims会静默降级
不配 ValidTimeFunc 就等于放弃 exp/nbf/iat 校验
echo-jwt 默认调用 token.Claims.(jwt.MapClaims).Valid(),但它内部的时间校验函数是空的——除非你手动传 jwt.WithValidTimeFunc,否则过期 token 会被当作有效。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
- 正确做法:在
echo.JWTConfig的ContextSetUserFn或中间件外层加时间校验逻辑 - 或直接在
KeyFunc后补充:token.Claims.(jwt.MapClaims).VerifyExpiresAt(time.Now().Unix(), true) - 注意:exp 字段必须是秒级
int64,前端若传毫秒值(如Date.now()),需除以 1000 再写入
解析失败不处理就会 panic,且默认 recover 不返回 JSON
JWT 解析出错(签名无效、结构错误、kid 不匹配)时,echo-jwt 会调用 c.Error(err),但默认 middleware.Recover() 只打印日志、返回空白 HTML,前端收不到 401 响应。
- 必须显式拦截:
if err != nil { c.AbortWithStatusJSON(http.StatusUnauthorized, map[string]string{"error": "invalid token"}) } - 不要依赖
token, _ := jwt.Parse(...)这类忽略 error 的写法 - 若用自定义中间件替代 echo-jwt,记得在
defer func()中 recover panic,并统一转为 JSON 错误
查黑名单不能放在 echo-jwt 中间件里,得链式追加
echo-jwt/v4 完全无状态,它解析完就把 *jwt.Token 放进 c.Get("user"),但不会查 Redis 或 DB。所谓“黑名单”必须由你额外加一层中间件实现。
- 确保签发时设置了
jti:claims["jti"] = uuid.NewString() - 黑名单 key 推荐用
revoked:{jti},TTL 对齐 token 的exp - 新中间件中直接断言:
token := c.Get("user").(*jwt.Token),再取token.Claims.(jwt.MapClaims)["jti"] - Redis 查询必须用
GET,非空即拒绝:if val, _ := rdb.Get(ctx, "revoked:"+jti).Result(); val != "" { ... }
真正容易被忽略的是时钟漂移和并发漏检:服务端时间比客户端快几秒,会导致 token 实际未过期却被拒;用户登出后立刻重放旧 token,Redis 写入延迟可能让黑名单查询落空。这两个点不加补偿逻辑,上线后就会出 401 投诉。










