3. JWT 常见伪造攻击类型
JWT(JSON Web Token)作为无状态认证的主流方案,其安全性高度依赖实现方的签名验证逻辑与密钥管理。攻击者利用实现缺陷或配置疏漏,可绕过签名校验、伪造任意身份。本章系统梳理四种最常见的 JWT 伪造攻击类型,并给出对应的检测与防御要点。
3.1 攻击类型总览
| 攻击类型 | 核心原理 | 利用条件 | 危害等级 |
|---|---|---|---|
| alg=none 攻击 | 将 JWT 头部 alg 字段设为 none,使服务端跳过签名验证 |
服务端未强制校验 alg 白名单 | 严重 |
| 弱密钥爆破 | 使用常见弱密钥字典对 HS256 等对称签名进行暴力破解 | 密钥强度不足(如 secret、123456) |
高 |
| 密钥泄露 | 攻击者通过源码泄露、配置暴露、日志打印等方式获取签名密钥 | 密钥存储不当或 CI/CD 流程泄露 | 严重 |
| 算法混淆攻击 | 将头部 alg 从 RS256(非对称)改为 HS256(对称),用公钥作为 HMAC 密钥伪造签名 | 服务端未区分公钥/私钥用途,且允许算法切换 | 严重 |
alg 白名单校验,禁止接受 none 算法,并严格区分对称与非对称算法的密钥使用场景。
3.2 alg=none 攻击
这是最基础的 JWT 伪造手法。攻击者将 JWT 头部中的 alg 字段修改为 none,并移除签名部分,使 token 变为 header.payload.(尾部带点但无签名)。若服务端未对 alg 做白名单校验,则会直接信任该 token 的 payload 内容。
// 原始合法 JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.signature
// 伪造后的 JWT(alg=none)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4ifQ.
检测要点:
- 服务端必须维护一个允许的
alg白名单(如["HS256", "RS256"]),拒绝none及未注册算法。 - 在 JWT 解析库中,禁用自动降级到
none的行为(如 Java 的jjwt需设置.setAllowedClockSkew()并显式指定算法)。 - 使用
require(alg)或类似方法强制要求签名算法必须存在且合法。
3.3 弱密钥爆破
当 JWT 使用对称签名算法(如 HS256、HS384、HS512)时,密钥强度直接决定安全性。攻击者收集到一个合法 JWT 后,可使用 hashcat、jwt-cracker 等工具对签名进行离线字典爆破。常见弱密钥包括 secret、password、123456、jwt_secret 等。
- 长度 ≥ 256 位(32 字节)
- 使用密码学安全的随机数生成器(如
/dev/urandom) - 禁止硬编码在代码或配置文件中
- 定期轮换(建议 ≤ 90 天)
检测与防御:
- 在开发环境使用
jwt-cracker或hashcat -m 16500对测试密钥进行爆破验证,确保密钥强度达标。 - 生产环境部署密钥强度扫描工具,定期检查 JWT 密钥是否出现在公开泄露的密码库中。
- 优先使用非对称算法(RS256/ES256),即使公钥泄露也不会导致签名伪造。
3.4 密钥泄露
密钥泄露往往源于管理疏漏而非算法缺陷。常见泄露途径包括:
| 泄露途径 | 典型场景 | 检测方法 |
|---|---|---|
| 源码仓库泄露 | 密钥硬编码在 .env 或配置文件中,随代码提交到 Git |
使用 git-secrets、truffleHog 扫描历史提交 |
| 日志打印 | 调试日志中输出 JWT 签名密钥或完整 token | 日志脱敏规则检查,禁止打印密钥字段 |
| CI/CD 环境变量 | 构建流水线中明文传递密钥,被日志或工件捕获 | 使用密钥管理服务(KMS/Vault)注入密钥 |
| 反向代理/网关 | Nginx 或 API 网关配置中暴露 JWT 密钥 | 定期审计网关配置文件权限 |
3.5 算法混淆攻击
算法混淆攻击(Algorithm Confusion Attack)利用了 JWT 库对公钥/私钥用途的区分缺陷。攻击者将 JWT 头部 alg 从 RS256(非对称,使用私钥签名、公钥验证)改为 HS256(对称,使用同一密钥签名和验证)。若服务端使用公钥作为 HMAC 的验证密钥,攻击者即可用公开的公钥伪造任意 JWT。
1. 获取服务端公钥(通常通过 /.well-known/jwks.json 或硬编码)
2. 构造恶意 payload(如 {"user":"admin","role":"admin"})
3. 将头部 alg 改为 "HS256"
4. 使用公钥字符串作为 HMAC 密钥,对 header.payload 进行签名
5. 将伪造的 JWT 发送给服务端
6. 服务端使用公钥作为 HS256 密钥验证签名 → 验证通过
检测与防御:
- 服务端必须根据
alg字段选择对应的密钥类型:非对称算法使用公钥验证,对称算法使用独立密钥。 - 实现
alg白名单时,禁止同时允许对称和非对称算法混用(如同时允许 HS256 和 RS256)。 - 使用 JWT 库的
setSigningKey()方法时,明确指定密钥用途(如setPublicKey()与setSecretKey()分开)。 - 在服务端验证逻辑中,检查
alg是否与预期算法一致,不一致则直接拒绝。
3.6 攻击检测与错误码断言
在后端安全合规中,针对 JWT 伪造攻击应定义明确的错误码与断言规则,确保攻击行为可被记录、告警和阻断。
| 错误码 | 含义 | 触发条件 | 建议 HTTP 状态码 |
|---|---|---|---|
JWT_ALG_NONE |
检测到 alg=none 攻击 | JWT 头部 alg 为 none 或未在白名单中 | 401 Unauthorized |
JWT_WEAK_KEY |
检测到弱密钥签名 | 签名验证通过但密钥强度低于安全基线 | 401 Unauthorized |
JWT_KEY_LEAK |
密钥疑似泄露 | 同一密钥在短时间内被多个不同来源使用 | 500 Internal Server Error |
JWT_ALG_CONFUSION |
检测到算法混淆攻击 | alg 与密钥类型不匹配(如 RS256 使用对称密钥验证) | 401 Unauthorized |
JWT_SIGNATURE_INVALID |
签名验证失败(通用) | 签名不匹配或 token 被篡改 | 401 Unauthorized |
- 所有 JWT 验证失败必须记录结构化日志,包含 token 头部、payload 摘要、来源 IP、时间戳。
- 对于
JWT_ALG_NONE和JWT_ALG_CONFUSION错误,应触发安全告警并临时封禁来源 IP(建议 5 分钟)。 - 错误码必须在 API 响应体中返回,禁止仅返回 HTTP 状态码而不提供错误原因。
3.7 本章小结
JWT 伪造攻击的核心在于服务端对 alg 字段和密钥用途的验证缺失。四种攻击类型中,alg=none 和 算法混淆 属于实现缺陷,弱密钥爆破 和 密钥泄露 属于密钥管理问题。后端架构师应在 JWT 验证中间件中实现以下安全基线:
- 强制
alg白名单,拒绝none及未注册算法。 - 区分对称与非对称算法的密钥验证逻辑,禁止混用。
- 密钥强度 ≥ 256 位,使用 KMS 管理,定期轮换。
- 定义标准错误码(如
JWT_ALG_NONE、JWT_ALG_CONFUSION),在响应体中返回并记录安全日志。