🔐 JWT 算法混淆:为什么“验签了”还是会被伪造

很多人第一次接触 JWT(JSON Web Token)时,会把注意力全放在“这个 token 有没有签名”。问题在于,真正危险的地方常常不是“有没有签”,而是“你拿什么方式去验这个签名”。JWT 头里有个 alg 字段,用来声明签名算法,比如 HS256RS256。如果服务端天真地相信这个字段,攻击者就可能把原本应该用非对称密钥校验的 token,改成对称算法去处理,最后把公开的公钥当成 HMAC 密钥来伪造签名,这就是经典的算法混淆。

这事会发生,不是因为 JWT 天生不安全,而是因为很多库早期设计得太“灵活”了。开发者把“支持多种算法”当成功能,结果把“由谁决定算法”这个控制权交给了用户输入。用户发来的 token 头里写什么,后端就按什么验,这就等于把门锁类型也交给访客自己选。只要系统同时支持 RS256HS256,又没有把某个 issuer、某条认证链路、某个 key 和固定算法绑定起来,攻击面就出来了。

现实里的防法也不复杂,但必须硬。第一,服务端不要从 token 里“学习”该用什么算法,而是自己预先写死允许的算法,比如这个服务只接受 RS256,那看到别的算法直接拒绝。第二,key 和算法要绑定,RSA 公钥就只能走 RSA 验签,绝不能被拿去做 HMAC。第三,别把“支持多算法”当兼容性优点,认证链路越单一越安全。第四,选成熟库时看默认行为,凡是允许 alg=none、自动降级、自动猜算法的,都是坑。

🧪 你在审一个登录系统,设计文档写着“统一使用 JWT”。代码里验签函数直接读取 token header 里的 alg,然后从配置里取一把 public key 去验。开发者说“反正 public key 本来就是公开的,没问题”。这里最致命的风险是什么?algHS256

💡 核心记忆:认证里最危险的不是没校验,而是把“怎么校验”这件事交给攻击者决定。

#Security