3. JWT 常见漏洞:alg=none 攻击、弱密钥爆破、kid 注入、jku/jwk 头部篡改
在压测场景中,JWT 的安全漏洞往往是性能瓶颈之外的“隐形杀手”。攻击者利用 JWT 标准实现中的缺陷,可以绕过认证、伪造身份,甚至直接接管系统。本章深入剖析四种最危险的 JWT 漏洞,帮助你在压测诊断中快速定位安全风险。
3.1 漏洞全景与攻击链路
JWT 漏洞的核心在于 服务端对令牌的信任假设 与 实际校验逻辑 之间的差距。攻击者通常通过篡改 JWT 头部、爆破密钥或注入恶意数据来实施攻击。下图展示了四种漏洞的攻击入口与影响范围:
3.2 alg=none 攻击
漏洞原理:JWT 标准允许头部 alg 字段值为 none,表示不使用签名。如果服务端校验逻辑未强制要求签名算法,攻击者可将 alg 改为 none 并移除签名部分,直接伪造任意 payload。
压测诊断要点: 在压测脚本中构造
alg: none 的 JWT 请求,观察服务端是否返回 200 而非 401。如果通过,说明存在严重安全缺陷。
攻击示例:
// 原始 JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
// 篡改后 JWT(alg=none,移除签名)
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkF0dGFja2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.
| 检测方法 | 预期结果 | 压测影响 |
|---|---|---|
| 发送 alg=none 的 JWT | 服务端应返回 401 Unauthorized | 若返回 200,压测结果完全不可信 |
| 发送空签名 JWT | 服务端应拒绝并记录告警 | 可能触发异常处理路径,影响性能基线 |
3.3 弱密钥爆破
漏洞原理:使用 HS256(HMAC-SHA256)对称签名时,如果密钥强度不足(如 secret、123456),攻击者可通过离线字典爆破还原密钥,进而伪造任意令牌。
压测建议: 在压测环境中使用
hashcat 或 jwt_tool 对已知 JWT 进行密钥爆破测试。若能在 1 分钟内破解,说明密钥强度严重不足。
常见弱密钥示例:
secret、key、password123456、qwerty、adminjwt_secret、my_secret_key- 长度小于 32 字符的随机字符串
密钥强度对比:
| 密钥类型 | 示例 | 爆破难度 | 压测风险等级 |
|---|---|---|---|
| 弱密钥 | secret123 |
秒级破解 | 极高 |
| 中等密钥 | MyApp!2024#Secret |
小时级破解 | 高 |
| 强密钥 | 32 字节随机 Base64 | 不可行 | 低 |
3.4 kid 注入攻击
漏洞原理:JWT 头部中的 kid(Key ID)用于指定密钥标识。如果服务端将 kid 直接拼接到文件路径或 SQL 查询中,攻击者可注入特殊字符实现路径遍历或 SQL 注入。
攻击向量分类:
- 路径遍历注入:
kid: ../../etc/passwd或kid: /dev/null - SQL 注入:
kid: ' OR '1'='1 - 命令注入:
kid: ; cat /etc/shadow
压测诊断方法: 在压测脚本中构造包含特殊字符的
kid 值,观察服务端响应状态码、响应体错误信息以及响应时间。若出现 500 错误或异常延迟,说明存在注入风险。
安全实现对比:
| 实现方式 | 代码示例 | 安全性 |
|---|---|---|
| 直接拼接 | fs.readFile('/keys/' + kid) |
危险 |
| 白名单校验 | if (!allowedKids.includes(kid)) reject() |
安全 |
| UUID 格式校验 | /^[a-f0-9-]{36}$/.test(kid) |
安全 |
3.5 jku/jwk 头部篡改
漏洞原理:JWT 支持通过 jku(JWK Set URL)或 jwk(JSON Web Key)头部动态指定公钥。如果服务端未验证 jku 的 URL 来源或直接信任 jwk 中的公钥,攻击者可提供自己控制的公钥,从而用对应的私钥签名任意令牌。
攻击流程:
- 攻击者生成自己的 RSA 密钥对
- 构造 JWT 头部,将
jwk设置为自己的公钥 - 使用自己的私钥对 payload 签名
- 服务端使用
jwk中的公钥验签,验证通过
压测诊断要点: 在压测请求中插入自定义
jwk 字段,使用自签名私钥生成 JWT。如果服务端接受该令牌,说明存在严重信任缺陷。
jku 安全校验清单:
| 校验项 | 说明 | 压测验证方法 |
|---|---|---|
| URL 白名单 | 只允许从可信域名获取 JWK | 构造外部 URL 观察是否被拒绝 |
| HTTPS 强制 | 禁止使用 HTTP 协议 | 使用 http:// 链接测试 |
| 缓存策略 | 对 JWK 进行缓存并设置 TTL | 压测中观察重复请求的耗时变化 |
| 公钥指纹校验 | 验证 JWK 的 thumbprint | 篡改公钥后发送请求 |
3.6 压测场景中的漏洞诊断清单
在压测执行前,建议将以下诊断项纳入测试用例:
| 漏洞类型 | 诊断用例 | 预期安全行为 | 压测关注指标 |
|---|---|---|---|
| alg=none | 发送 alg:none 且无签名的 JWT | 返回 401 | 响应时间、错误率 |
| 弱密钥爆破 | 使用常见弱密钥字典离线爆破 | 无法在合理时间内破解 | 密钥长度、签名算法 |
| kid 注入 | 发送 kid 含路径遍历字符 | 返回 400 或 401 | 异常响应比例 |
| jku/jwk 篡改 | 发送自签名 jwk 令牌 | 返回 401 | 验签耗时、CPU 使用率 |
最佳实践: 在压测脚本中集成 JWT 安全检测模块,每次压测前自动执行一轮漏洞扫描。这不仅能发现安全问题,还能确保压测数据不被伪造令牌污染。