做过后端开发的朋友大概率都遇到过这种场景:项目马上要提测了,安全测试那边甩过来一份报告,标题写着“JWT鉴权链路存在高危风险”,下面跟着弱密钥、算法混淆、token可伪造几个大字,然后你的周末就没了。JWT本身只是一个格式规范,它不是框架,也不替你做安全决策,用得好是登录态管理利器,用得糙就是给攻击者留后门。
这篇内容是我这几年在Spring Boot、.NET Core和一些SPA项目里和JWT交手的经验总结,会从攻击原理一路聊到框架落地,把jwt破解、jwt伪造的常见路径、token续签怎么实现、Swagger要不要放行这类反复踩坑的点都过一遍。不管你是刚接触JWT还是已经被线上事故磨了一轮,应该都能从中找到对应的解法。
1. 先看懂攻击面:JWT为什么会被破解和伪造
1.1 从“三段式”结构看攻击面
JWT整体上是一串用点号分隔的字符串,比如:
code复制eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
从左到右分别是Header、Payload、Signature。Header里保存token类型和签名算法,Payload里放用户相关声明,Signature是用密钥对前两段内容做的签名。
关键点在于:前两段只是Base64Url编码,不是加密。任何一个jwt在线解析工具都能直接读取里面的内容,甚至直接帮你把第三段签名去掉改成“无签名”版本。很多人第一次用JWT时,看到payload里可以塞任意JSON,就顺手把用户手机号、邮箱、角色、部门全放进去了,这就是典型的“把签名当成加密”的误用。
签名只保证token的完整性,不保证内容的机密性。服务端验签成功只说明“这段内容确实由持有密钥的一方生成,且没有被改过”,但任何能拿到token的人都能看见payload里的所有字段。理解这一点是后面所有安全加固的基础。
1.2 攻击者最常用的四条攻击路径
攻击者拿到一个JWT后,通常会按下面几条路径去试。
第一是alg none攻击。把Header里的alg改成none,然后把签名部分清空,直接提交给服务端。理论上服务端验签时必须拒绝这种请求,但很多早期JWT库在实现时,看到alg是none就直接跳过签名校验。只要业务代码里没有显式拒绝none,等于攻击者可以随意构造身份登录。我自己在测试一些老项目时,用这个方法成功率并不低,说明它不是书本上的冷门漏洞。
第二是算法混淆攻击。这是最恶心的一种。服务端如果用RS256这类非对称算法验签,公钥本身是公开的,可以被任何人拿到。攻击者把Header里的alg改成HS256,如果服务端没有校验“当前token声明使用的算法”和“服务端配置的算法”是否一致,就可能直接用公钥作为HMAC对称密钥来验证签名。由于公钥是公开的,攻击者也能拿公钥当密钥签发一个新token,服务端验签照样通过。
第三是弱密钥爆破。HS256的签名和验签用的是同一个对称密钥,密钥一旦短小、可预测,攻击者本地就可以跑常见密钥词表,用hashcat这类工具瞬间爆破出真正的secret。很多网上的教程代码直接写死一个“mySecret”,项目上线也忘记改,等于把门锁钥匙挂在门上。
第四是水平越权与信息泄露。这个问题其实和JWT被伪造无关,但同样由JWT使用不当引发。当payload里放了userId,而接口只校验了“登录态有效”,没有校验“这个userId是不是当前登录用户的userId”,攻击者只需要改动payload里的userId,再拿着自己的token去访问别人的数据。有些团队连签名都不换,只改payload就能越权,这种情况我见过不止一次。
所以你看,真正出问题的往往不是JWT算法本身,而是实现方的三个失误:过度信任请求里带来的alg、使用弱密钥、在payload里塞了不该塞的数据。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 开发阶段堵漏洞:密钥、过期与payload内容管理
2.1 密钥的生成、存储与轮换,别把代码示例的secret带进生产
先说结论:HS256场景下,
