ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

JWT能解码不等于可信:服务端验签最容易漏掉的4件事

JWT能解码不等于可信:服务端验签最容易漏掉的4件事 把JWT粘贴进调试工具立刻就能看到用户ID、角色和过期时间。第一次接触JWT的人很容易产生两个误解能解码说明已经验证过或者载荷看起来正常就可以相信。实际上JWT常见的JWS形式主要解决的是完整性和来源验证并不负责隐藏载荷。头部和载荷只是Base64URL编码任何拿到令牌的人都能读取也能自行修改。服务端只有在完成签名和声明校验后才能把其中的数据用于授权决策。遗漏一让令牌自己决定验证算法JWT头部中的alg描述签名算法但它来自客户端提交的令牌不能被当作可信配置。服务端应该在代码或配置中明确允许的算法集合并让库拒绝其他算法。错误思路是“令牌写HS256我就按HS256验写RS256我就按RS256验。”这会把安全策略交给不可信输入。历史上出现过none算法接受问题以及对称、非对称算法混淆问题。成熟JWT库通常提供算法白名单参数使用时仍需显式配置不能只依赖默认值。正确的问题不是“这个令牌声称用了什么算法”而是“这个接口只允许哪一种算法和哪一组密钥”。遗漏二签名通过却拿错了密钥多租户或多身份提供方场景中系统会根据kid选择密钥。kid同样来自令牌头部只能作为查找索引不能直接拼接为文件路径、数据库语句或远程地址。密钥选择至少需要这些约束只从受信任的本地密钥集或固定JWKS地址读取身份提供方与密钥集建立固定映射未知kid直接拒绝不临时从任意URL下载JWKS缓存有合理刷新策略但失败时不能悄悄跳过验签不把测试环境密钥带入生产。如果系统同时接入多个发行方还要防止“甲系统签发的合法令牌被乙系统接口接受”。签名正确只说明某把钥匙签过不能说明它属于当前业务信任域。遗漏三只验签不验证声明签名验证回答“内容是否被持有密钥的一方签发且未被修改”但并没有自动回答“现在能否在这个接口使用”。服务端还应根据业务验证标准声明iss发行方是否为预期身份系统aud令牌是否签发给当前服务exp令牌是否过期nbf是否已经到允许使用的时间必要时检查iat、jti、会话状态和权限版本。时钟允许少量偏差可以提高稳定性但偏差窗口必须明确且足够小。不能为了“解决偶发过期”把校验窗口放大到几个小时。权限字段也要谨慎。令牌里的roleadmin即使签名有效也只代表签发时的状态。如果管理员权限已被撤销而访问令牌仍有很长有效期业务就会继续放行。高风险操作可结合短时令牌、服务端会话状态或权限版本进行二次判断。遗漏四只设计签发不设计轮换和撤销密钥不会永远安全。生产系统需要提前考虑轮换新密钥何时开始签发旧密钥保留多久用于验证泄露时如何紧急撤销以及各服务如何同步密钥状态。一个常见策略是让新旧密钥在短时间内同时可验证新令牌只用新密钥签发等待旧令牌自然过期后再移除旧密钥。但如果确认密钥泄露就不能继续等待自然过期应立即撤销并评估所有受影响令牌。访问令牌有效期越长泄露后的风险窗口越大。刷新令牌则应使用更严格的存储、绑定、轮换和重放检测机制。不要把访问令牌、刷新令牌或完整Authorization头写进普通应用日志排错时可以记录令牌指纹、发行方和校验失败类别。代码审计时看什么不要只搜索verify()是否被调用还要沿数据流检查算法是否由服务端固定密钥来源是否受信任iss和aud是否与当前服务绑定时间声明是否强制验证验证失败是否真正中止请求载荷字段是否在验签前被用于查库、路由或授权日志、错误响应和监控是否泄露令牌内容。尤其要留意“先解码读取租户ID再决定使用哪套校验规则”的逻辑。预读取有时是架构需要但预读取结果必须被视为不可信提示不能直接改变安全边界。上线前的最小检查清单使用维护中的JWT库不自行实现密码算法固定允许算法不接受none校验签名、发行方、受众和时间声明限制kid与JWKS来源访问令牌短期有效密钥可轮换高风险权限变更具备及时失效机制日志不记录完整令牌为错误算法、错误受众、过期令牌和未知密钥编写负向测试。JWT真正危险的地方往往不是密码学被攻破而是验证流程少做了一步。把“解码、验签、声明校验、授权”当成四个不同阶段代码审计时会清楚很多。如果你准备系统学习Web安全、代码审计和身份认证可以用这份清单给每个实验接口补一组负向测试。马士兵网络安全课程的相关学习入口可在这里查看。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进