本文目录导读:

JWT漏洞全面防护与修复指南:从原理到实战的完整安全策略
目录导读
- JWT漏洞的本质:为什么你的令牌可能不安全?
- 常见JWT攻击手法详解(算法混淆、密钥爆破、空签名攻击)
- 防护修复实战方案(代码级安全配置+架构加固)
- 问答专区:开发者最关心的5个JWT安全难题
- 长效监控与检测工具推荐
JWT漏洞的本质:为什么你的令牌可能不安全?
JSON Web Token(JWT)作为无状态认证的“通用语言”,其安全性高度依赖实现细节,根据OWASP 2023年Top 10安全风险,JWT相关漏洞已进入“关键漏洞”列表,核心问题往往出在三部分结构(Header、Payload、Signature)的信任机制上:
- 算法混淆攻击:当服务端未严格校验
alg字段时,攻击者可将RS256改为HS256,并利用已知公钥作为HMAC密钥伪造令牌。 - 密钥泄露与弱密钥:硬编码密钥、使用弱口令(如
123456)或未定期轮换密钥。 - 空签名攻击:若服务端未验证签名,攻击者可移除Signature部分直接伪造合法令牌。
真实案例:2022年某电商平台因JWT的
jku头字段未校验可信来源,导致攻击者通过自托管密钥JWK文件伪造管理员令牌,泄露260万用户数据。
常见JWT攻击手法详解
1 算法混淆攻击(Algorithm Confusion)
攻击原理:JWT库通常支持多种签名算法,当服务端使用非对称算法(RS256)时,攻击者将Header中的alg改为对称算法(HS256),并携带公钥字符串作为密钥签名,若服务端未区分公私钥使用场景,会使用公钥进行HMAC验证——而公钥是公开的。
防护要点:
// 错误示例:无算法白名单
jwt.verify(token, publicKey);
// 安全示例:显式指定算法
jwt.verify(token, publicKey, { algorithms: ['RS256'] });
2 密钥爆破与弱密钥攻击
- 弱密钥字典:
HS256密钥若少于32字节且为常见字符串,可在2小时内被GPU爆破。 - 公钥泄露:在某些配置中,
.well-known/jwks.json公开了公钥,攻击者可离线爆破签名。
防护验收指标:
- HS系列密钥熵值≥256位(如
openssl rand -hex 32生成) - RS系列密钥长度≥2048位
- 每90天轮换密钥
3 空签名与“none”算法攻击
部分旧版库允许alg: "none"(无签名),此时Payload可直接被篡改。
修复方案:
# 在PyJWT中必须禁用none算法
jwt.decode(token, key, algorithms=['HS256'], options={'verify_signature': True})
防护修复实战方案
1 服务端硬编码防御
// Java (jjwt库) 安全示例
Jwts.parserBuilder()
.setSigningKey(secretKey)
.requireIssuer("your-app")
.setAllowedClockSkewSeconds(30) // 限制时钟偏差
.build()
.parseClaimsJws(token);
2 架构级强化
- 黑名单机制:在Redis中维护已注销JWT的
jti列表,每个令牌设置5分钟有效期(防止内存膨胀)。 - 签名密钥分层:使用HS256做短期令牌(Access Token),RS256做长期刷新令牌(Refresh Token)。
- jku与x5u验证:若使用JWK URL,必须对证书链做SSL Pinning并校验域名白名单。
3 避免令牌在URL中传输
危险行为:通过GET请求传递JWT(易被Referer泄露、日志记录)。
安全做法:始终使用Authorization: Bearer <token>头,并开启HTTPS + HSTS。
问答专区:开发者最关心的5个JWT安全难题
Q1:我的JWT使用了HS256,是不是比RS256更安全?
A:不是!HS256要求对称密钥绝对保密,但RS256的公钥可公开,密钥管理更灵活,核心风险不在算法本身,而在密钥强度和验证逻辑。建议:对外接口用RS256,内部服务可用HS256但需密钥分发管道安全。
Q2:如何防止JWT被重放攻击?
A:必须包含以下字段:
exp(过期时间):Access Token建议15分钟nbf(不可用时间):防止提前使用jti(唯一标识):结合服务端黑名单做一次使用
重要:永远不要禁用过期验证。
Q3:我的程序跑在多个服务器上,JWT的密钥如何同步?
A:使用密钥管理服务(AWS KMS / HashiCorp Vault)集中存储密钥,或采用RS256算法(所有服务器只有公钥)。绝对不要把密钥硬编码在配置文件中。
Q4:JWT的payload中能存敏感信息吗?
A:不能!Base64编码并非加密,任何人都可解码,若需存储,务必用JWE(JSON Web Encryption)加密payload区,或仅存储用户ID+角色,敏感数据通过数据库查询。
Q5:我的旧系统用了“alg: none”,怎么迁移?
A:分两步:
- 在代码层添加
algorithms: ['HS256']白名单,并拒绝none - 强制所有客户端刷新令牌(让旧token自然失效)
救命工具:使用jwt-killer扫描旧令牌并发布黑名单。
长效监控与检测工具推荐
- 自动化扫描:安装
jwt_tool(Python库),可检测算法混淆、密钥强度、过期配置jwt_tool eyJhbGciOiJSUzI1NiIs... -T -v
- 运行时监控:在网关层记录
jti唯一性冲突和无效签名次数,阈值设定为每分钟超过10次则触发告警。 - 红蓝对抗演练:每月利用
jwt-probe模拟空签名攻击,检验响应机制。
JWT安全的黄金法则
- 永远指定算法白名单(拒绝
none) - 密钥强度≥256位(HS)或≥2048位(RS)
- 启用exp、nbf、jti三要素
- 公钥不信任、私钥不落地(使用密钥中心)
- 配合黑名单+短有效期实现“准无状态”
JWT本身是安全的,漏洞全部出自实现不当,对照本文的“5个问答”自检你的代码,并立即修复已知风险点——攻击者只需要一个弱算法或空签名,就能摧毁整个认证体系。