接收Bearer Token时JWT冲突的成因及规避方案
JWT令牌验证异常:不同令牌通过验证的原因分析
核心原因:Base64URL编码的冗余位容错
JWT的签名部分是哈希值(比如HS256算法生成的256位二进制数据)经过Base64URL编码得到的字符串。Base64URL编码会把二进制数据按每6位一组转换为字符,当二进制总位数不是6的整数倍时,会在最后一组补0凑够6位——这部分补的0就是冗余填充位。
在验证签名时,PyJWT(Django REST Framework JWT、FastAPI的PyJWT实现都基于这个库)会将令牌的签名部分解码回二进制数据,此时会自动忽略最后一组的填充冗余位。所以:
- 如果修改签名末尾字符的冗余位(也就是补0的那几位),解码后的二进制哈希值和原始完全一致,验证自然通过;
- 如果修改的是有效数据位(非填充的部分),解码后的哈希值会和服务器重新计算的哈希值不匹配,验证就会失败。
对应场景的具体解释
你遇到的末尾为c/d/e的令牌能通过验证,是因为这几个字符对应的6位编码里,前4位完全相同(对应原始哈希的有效位),只有最后两位(填充冗余位)不一样;而末尾为b/g的字符,前4位和原始字符c的前4位不同,解码后的哈希值和原始不一致,所以验证失败。
处理建议
这是Base64URL编码的特性导致的,并非JWT验证逻辑的漏洞。如果需要严格匹配令牌字符串,可以在验证通过后额外对比令牌的原始字符串和服务器生成的令牌是否完全一致,但这会破坏JWT的无状态特性,一般不推荐。更合理的做法是:
- 确保令牌生成、传输过程的安全性,避免令牌被篡改;
- 启用JWT的过期时间(
exp声明),限制令牌的有效时长,降低篡改后的令牌被滥用的风险。
内容的提问来源于stack exchange,提问作者Nazmus Sakib Sibly
相关产品推荐
相关产品推荐

