opencode-api-security-testing 5.0.0 → 5.2.0
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 +6 -0
- package/agents/api-cyber-supervisor.md +5 -3
- package/package.json +1 -1
- package/postinstall.mjs +181 -6
- package/src/index.ts +165 -0
- package/src/tools/endpoint-discover.ts +325 -0
- package/src/tools/report-generator.ts +355 -0
- package/src/utils/env-checker.ts +264 -0
- package/references/references/README.md +0 -72
- package/references/references/asset-discovery.md +0 -119
- package/references/references/fuzzing-patterns.md +0 -129
- package/references/references/graphql-guidance.md +0 -108
- package/references/references/intake.md +0 -84
- package/references/references/pua-agent.md +0 -192
- package/references/references/report-template.md +0 -156
- package/references/references/rest-guidance.md +0 -76
- package/references/references/severity-model.md +0 -76
- package/references/references/test-matrix.md +0 -86
- package/references/references/validation.md +0 -78
- package/references/references/vulnerabilities/01-sqli-tests.md +0 -1128
- package/references/references/vulnerabilities/02-user-enum-tests.md +0 -423
- package/references/references/vulnerabilities/03-jwt-tests.md +0 -499
- package/references/references/vulnerabilities/04-idor-tests.md +0 -362
- package/references/references/vulnerabilities/05-sensitive-data-tests.md +0 -466
- package/references/references/vulnerabilities/06-biz-logic-tests.md +0 -501
- package/references/references/vulnerabilities/07-security-config-tests.md +0 -511
- package/references/references/vulnerabilities/08-brute-force-tests.md +0 -457
- package/references/references/vulnerabilities/09-vulnerability-chains.md +0 -465
- package/references/references/vulnerabilities/10-auth-tests.md +0 -537
- package/references/references/vulnerabilities/11-graphql-tests.md +0 -355
- package/references/references/vulnerabilities/12-ssrf-tests.md +0 -396
- package/references/references/vulnerabilities/README.md +0 -148
- package/references/references/workflows.md +0 -192
- package/src/src/index.ts +0 -535
|
@@ -1,466 +0,0 @@
|
|
|
1
|
-
# 敏感信息泄露测试
|
|
2
|
-
|
|
3
|
-
## 1. 概述
|
|
4
|
-
|
|
5
|
-
敏感信息泄露包括 API 响应中包含不应暴露的敏感数据,以及错误消息中泄露的系统内部信息。
|
|
6
|
-
|
|
7
|
-
**危险等级**: 中
|
|
8
|
-
|
|
9
|
-
## 2. 敏感字段分类
|
|
10
|
-
|
|
11
|
-
### 2.1 认证相关
|
|
12
|
-
|
|
13
|
-
| 字段 | 风险 |
|
|
14
|
-
|------|------|
|
|
15
|
-
| password | 密码明文 |
|
|
16
|
-
| passwordHash | 密码哈希 |
|
|
17
|
-
| token | 会话令牌 |
|
|
18
|
-
| sessionId | 会话ID |
|
|
19
|
-
| refreshToken | 刷新令牌 |
|
|
20
|
-
| secretKey | 密钥 |
|
|
21
|
-
| apiKey | API密钥 |
|
|
22
|
-
| privateKey | 私钥 |
|
|
23
|
-
|
|
24
|
-
### 2.2 用户信息
|
|
25
|
-
|
|
26
|
-
| 字段 | 风险 |
|
|
27
|
-
|------|------|
|
|
28
|
-
| idCard | 身份证号 |
|
|
29
|
-
| phone | 手机号 |
|
|
30
|
-
| email | 邮箱 |
|
|
31
|
-
| address | 地址 |
|
|
32
|
-
| bankCard | 银行卡号 |
|
|
33
|
-
| realName | 真实姓名 |
|
|
34
|
-
|
|
35
|
-
### 2.3 金融相关
|
|
36
|
-
|
|
37
|
-
| 字段 | 风险 |
|
|
38
|
-
|------|------|
|
|
39
|
-
| balance | 账户余额 |
|
|
40
|
-
| credit | 信用额度 |
|
|
41
|
-
| salary | 工资 |
|
|
42
|
-
| orderNo | 订单号(可预测) |
|
|
43
|
-
|
|
44
|
-
## 3. 测试方法
|
|
45
|
-
|
|
46
|
-
### 3.1 登录响应检查
|
|
47
|
-
|
|
48
|
-
```bash
|
|
49
|
-
POST /api/login
|
|
50
|
-
{"username": "admin", "password": "xxx"}
|
|
51
|
-
|
|
52
|
-
# 检查响应是否包含
|
|
53
|
-
{
|
|
54
|
-
"code": 200,
|
|
55
|
-
"token": "xxx", # ← 泄露
|
|
56
|
-
"refreshToken": "xxx", # ← 泄露
|
|
57
|
-
"expireTime": 3600
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### 3.2 用户信息响应检查
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
GET /api/user/info
|
|
65
|
-
Headers: {"Authorization": "Bearer xxx"}
|
|
66
|
-
|
|
67
|
-
# 检查响应
|
|
68
|
-
{
|
|
69
|
-
"userId": 100,
|
|
70
|
-
"username": "admin",
|
|
71
|
-
"password": "明文密码", # ← 严重泄露
|
|
72
|
-
"passwordHash": "xxx", # ← 泄露
|
|
73
|
-
"phone": "138****8888", # ← 脱敏(安全)
|
|
74
|
-
"idCard": "110***********1234" # ← 脱敏(安全)
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 3.3 配置文件检查
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
GET /api/config
|
|
82
|
-
GET /api/system/config
|
|
83
|
-
GET /api/settings
|
|
84
|
-
|
|
85
|
-
# 检查是否返回
|
|
86
|
-
{
|
|
87
|
-
"dbPassword": "xxx",
|
|
88
|
-
"apiSecret": "xxx",
|
|
89
|
-
"jwtSecret": "xxx"
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### 3.4 Swagger/API 文档检查
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
GET /swagger-ui.html
|
|
97
|
-
GET /doc.html
|
|
98
|
-
GET /v2/api-docs
|
|
99
|
-
GET /swagger.json
|
|
100
|
-
|
|
101
|
-
# 检查是否可访问
|
|
102
|
-
# 可访问 → 存在信息泄露
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### 3.5 错误信息泄露
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
# 触发错误
|
|
109
|
-
GET /api/user?id=999
|
|
110
|
-
|
|
111
|
-
# SQL 错误
|
|
112
|
-
{"error": "You have an error in your SQL syntax near 'xxx'"}
|
|
113
|
-
|
|
114
|
-
# Java 堆栈
|
|
115
|
-
{"error": "java.lang.NullPointerException at com.xxx.UserService.getUser(UserService.java:45)"}
|
|
116
|
-
|
|
117
|
-
# 路径泄露
|
|
118
|
-
{"error": "FileNotFoundException: /app/config/production/database.yml"}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
## 4. 错误信息指纹
|
|
122
|
-
|
|
123
|
-
| 数据库 | 错误特征 |
|
|
124
|
-
|--------|----------|
|
|
125
|
-
| MySQL | `You have an error in your SQL syntax` |
|
|
126
|
-
| PostgreSQL | `ERROR: syntax error at or near` |
|
|
127
|
-
| SQL Server | `Unclosed quotation mark` |
|
|
128
|
-
| Oracle | `ORA-01756` |
|
|
129
|
-
| MongoDB | `MongoDB.Driver` |
|
|
130
|
-
| Redis | `ERR wrong number of arguments` |
|
|
131
|
-
|
|
132
|
-
| 语言/框架 | 错误特征 |
|
|
133
|
-
|-----------|----------|
|
|
134
|
-
| Java | `java.lang.*Exception` |
|
|
135
|
-
| Python | `Traceback (most recent call last)` |
|
|
136
|
-
| Node.js | `ReferenceError: xxx is not defined` |
|
|
137
|
-
| .NET | `System.NullReferenceException` |
|
|
138
|
-
| Spring | `at com.xxx.controller` |
|
|
139
|
-
|
|
140
|
-
## 5. 脱敏检测
|
|
141
|
-
|
|
142
|
-
### 5.1 常见脱敏模式
|
|
143
|
-
|
|
144
|
-
| 类型 | 示例 |
|
|
145
|
-
|------|------|
|
|
146
|
-
| 手机号 | `138****8888` |
|
|
147
|
-
| 身份证 | `110***********1234` |
|
|
148
|
-
| 银行卡 | `**** **** **** 1234` |
|
|
149
|
-
| 邮箱 | `t***@example.com` |
|
|
150
|
-
| 密码 | `******` |
|
|
151
|
-
|
|
152
|
-
### 5.2 检测脱敏
|
|
153
|
-
|
|
154
|
-
```python
|
|
155
|
-
import re
|
|
156
|
-
|
|
157
|
-
def check_sensitive_mask(text):
|
|
158
|
-
# 手机号未脱敏
|
|
159
|
-
if re.search(r'1[3-9]\d{9}', text):
|
|
160
|
-
return False, "手机号未脱敏"
|
|
161
|
-
|
|
162
|
-
# 身份证未脱敏
|
|
163
|
-
if re.search(r'\d{17}[\dXx]', text):
|
|
164
|
-
return False, "身份证号未脱敏"
|
|
165
|
-
|
|
166
|
-
# 密码字段存在
|
|
167
|
-
if 'password' in text.lower() and 'null' not in text:
|
|
168
|
-
return False, "密码字段存在"
|
|
169
|
-
|
|
170
|
-
return True, "已脱敏"
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## 6. 关联漏洞
|
|
174
|
-
|
|
175
|
-
| 后续漏洞 | 利用路径 |
|
|
176
|
-
|----------|----------|
|
|
177
|
-
| 账户接管 | 泄露的密码可用于登录 |
|
|
178
|
-
| 社工攻击 | 手机号、邮箱用于钓鱼 |
|
|
179
|
-
| 横向移动 | 泄露的密钥用于内网渗透 |
|
|
180
|
-
|
|
181
|
-
## 7. 测试检查清单
|
|
182
|
-
|
|
183
|
-
```
|
|
184
|
-
□ 检查登录响应是否泄露 token/refreshToken
|
|
185
|
-
□ 检查用户信息响应是否泄露 password
|
|
186
|
-
□ 检查配置文件响应是否泄露密钥
|
|
187
|
-
□ 检查 Swagger/API 文档是否可访问
|
|
188
|
-
□ 检查错误消息是否泄露技术栈
|
|
189
|
-
□ 检查错误消息是否泄露数据库类型
|
|
190
|
-
□ 检查错误消息是否泄露文件路径
|
|
191
|
-
□ 检查是否对敏感字段进行脱敏
|
|
192
|
-
□ 评估泄露的信息可造成的危害
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## 8. 敏感信息检测脚本
|
|
196
|
-
|
|
197
|
-
```python
|
|
198
|
-
import requests
|
|
199
|
-
import re
|
|
200
|
-
|
|
201
|
-
SENSITIVE_PATTERNS = [
|
|
202
|
-
(r'password["\s:]+["\'][^"\']+["\']', '密码明文'),
|
|
203
|
-
(r'passwordHash["\s:]+["\'][^"\']+["\']', '密码Hash'),
|
|
204
|
-
(r'token["\s:]+["\'][a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+["\']', 'JWT Token'),
|
|
205
|
-
(r'secretKey["\s:]+["\'][^"\']+["\']', '密钥'),
|
|
206
|
-
(r'apiKey["\s:]+["\'][^"\']+["\']', 'API密钥'),
|
|
207
|
-
(r'1[3-9]\d{9}', '手机号'),
|
|
208
|
-
(r'\d{17}[\dXx]', '身份证号'),
|
|
209
|
-
]
|
|
210
|
-
|
|
211
|
-
def scan_response(text):
|
|
212
|
-
findings = []
|
|
213
|
-
for pattern, name in SENSITIVE_PATTERNS:
|
|
214
|
-
matches = re.findall(pattern, text, re.IGNORECASE)
|
|
215
|
-
if matches:
|
|
216
|
-
findings.append((name, matches))
|
|
217
|
-
return findings
|
|
218
|
-
|
|
219
|
-
# 使用
|
|
220
|
-
resp = requests.get("http://api/user/info")
|
|
221
|
-
findings = scan_response(resp.text)
|
|
222
|
-
for name, matches in findings:
|
|
223
|
-
print(f"[FINDING] {name}: {matches}")
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## 9. 误报判断标准
|
|
227
|
-
|
|
228
|
-
### 9.1 核心判断原则
|
|
229
|
-
|
|
230
|
-
```
|
|
231
|
-
【重要】敏感信息泄露 ≠ 一定是漏洞!
|
|
232
|
-
|
|
233
|
-
判断逻辑:
|
|
234
|
-
1. 先确认接口是否需要认证
|
|
235
|
-
2. 再确认数据是否本来就应被该用户访问
|
|
236
|
-
3. 最后判断是否为"非预期"的敏感信息泄露
|
|
237
|
-
|
|
238
|
-
【真实泄露特征】
|
|
239
|
-
- 未认证接口返回用户敏感信息
|
|
240
|
-
- 响应中包含他人的隐私数据
|
|
241
|
-
- 配置文件返回数据库密码/API密钥
|
|
242
|
-
|
|
243
|
-
【正常情况(不是漏洞)】
|
|
244
|
-
- 登录响应返回token是正常功能
|
|
245
|
-
- 认证用户获取自己的信息是正常功能
|
|
246
|
-
- 公开接口返回公开信息是正常功能
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### 9.2 curl + 对比验证流程
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
# 1. 【必须先执行】获取正常响应基准
|
|
253
|
-
curl -s -H "Authorization: Bearer $TOKEN" \
|
|
254
|
-
http://api/user/info > sensitive_baseline.json
|
|
255
|
-
|
|
256
|
-
# 分析:正常响应应该包含什么?
|
|
257
|
-
cat sensitive_baseline.json | jq .
|
|
258
|
-
|
|
259
|
-
# 2. 检查脱敏情况
|
|
260
|
-
# 如果手机号是 138****8888 → 脱敏(安全)
|
|
261
|
-
# 如果手机号是 13800138000 → 未脱敏(可能漏洞)
|
|
262
|
-
|
|
263
|
-
# 3. 检查是否返回了不该返回的字段
|
|
264
|
-
# password字段存在 → 漏洞
|
|
265
|
-
# token字段存在 → 可能是正常(取决于用途)
|
|
266
|
-
|
|
267
|
-
# 4. 对比不同用户的响应
|
|
268
|
-
curl -s -H "Authorization: Bearer $TOKEN_A" \
|
|
269
|
-
http://api/user/info?userId=101 > user_101.json
|
|
270
|
-
|
|
271
|
-
curl -s -H "Authorization: Bearer $TOKEN_A" \
|
|
272
|
-
http://api/user/info?userId=102 > user_102.json
|
|
273
|
-
|
|
274
|
-
diff user_101.json user_102.json
|
|
275
|
-
# 如果响应完全相同 → 可能是返回了相同的数据(自己的数据)
|
|
276
|
-
# 如果响应中ID不同 → 确认访问了不同用户的数据 → 漏洞
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
### 9.3 敏感信息泄露判断矩阵
|
|
280
|
-
|
|
281
|
-
| 场景 | 响应内容 | 是否认证 | 判断 |
|
|
282
|
-
|------|----------|----------|------|
|
|
283
|
-
| 登录返回token | {"token": "xxx"} | 否 | ✅ 正常 |
|
|
284
|
-
| 用户查看自己信息 | {"phone": "138****8888"} | 是 | ✅ 脱敏正常 |
|
|
285
|
-
| 用户查看自己信息 | {"password": "xxx"} | 是 | ⚠️ 漏洞(不应返回) |
|
|
286
|
-
| 未认证获取用户列表 | [{"phone": "138xxx"}, ...] | 否 | ⚠️ 漏洞 |
|
|
287
|
-
| 公开接口返回手机号 | {"phone": "138xxx"} | 否 | ⚠️ 漏洞 |
|
|
288
|
-
| 配置文件返回密钥 | {"dbPassword": "xxx"} | 是 | ⚠️ 漏洞 |
|
|
289
|
-
|
|
290
|
-
### 9.4 Python脚本(敏感信息深度检测)
|
|
291
|
-
|
|
292
|
-
```python
|
|
293
|
-
import requests
|
|
294
|
-
import re
|
|
295
|
-
|
|
296
|
-
class SensitiveDataTester:
|
|
297
|
-
def __init__(self, target):
|
|
298
|
-
self.target = target
|
|
299
|
-
|
|
300
|
-
def check_masking(self, text, field_type='phone'):
|
|
301
|
-
"""
|
|
302
|
-
检测敏感信息是否脱敏
|
|
303
|
-
|
|
304
|
-
判断标准:
|
|
305
|
-
- 手机号:应该是 138****8888 格式
|
|
306
|
-
- 身份证:应该是 110***********1234 格式
|
|
307
|
-
- 邮箱:应该是 t***@example.com 格式
|
|
308
|
-
"""
|
|
309
|
-
patterns = {
|
|
310
|
-
'phone': r'1[3-9]\d{9}', # 未脱敏手机号
|
|
311
|
-
'idcard': r'\d{17}[\dXx]', # 未脱敏身份证
|
|
312
|
-
'email': r'\w+@\w+\.\w+', # 未脱敏邮箱
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
# 检查是否存在未脱敏的敏感信息
|
|
316
|
-
matches = re.findall(patterns.get(field_type, ''), text)
|
|
317
|
-
if matches:
|
|
318
|
-
# 检查是否是脱敏格式
|
|
319
|
-
masked_patterns = {
|
|
320
|
-
'phone': r'1\d{2}\*{4,}\d{4}', # 138****8888
|
|
321
|
-
'idcard': r'\d{3}\*{10,}\d{4}', # 110***********1234
|
|
322
|
-
}
|
|
323
|
-
masked = re.findall(masked_patterns.get(field_type, ''), text)
|
|
324
|
-
|
|
325
|
-
if len(matches) > len(masked):
|
|
326
|
-
return False, f"发现未脱敏的{field_type}: {matches}"
|
|
327
|
-
return True, "已脱敏"
|
|
328
|
-
return True, "未发现该类型信息"
|
|
329
|
-
|
|
330
|
-
def check_forbidden_fields(self, text):
|
|
331
|
-
"""
|
|
332
|
-
检查禁止返回的字段
|
|
333
|
-
|
|
334
|
-
【判断标准】
|
|
335
|
-
- password: 不应返回前端(无论是否脱敏)
|
|
336
|
-
- passwordHash: 不应返回前端
|
|
337
|
-
- secretKey/apiKey: 不应返回前端
|
|
338
|
-
"""
|
|
339
|
-
forbidden = ['password', 'passwordHash', 'secretKey', 'apiKey', 'privateKey']
|
|
340
|
-
found = []
|
|
341
|
-
|
|
342
|
-
text_lower = text.lower()
|
|
343
|
-
for field in forbidden:
|
|
344
|
-
if field in text_lower:
|
|
345
|
-
# 检查是否有值(不是null或空)
|
|
346
|
-
pattern = f'{field}["\s:]+["\']([^"\']{2,})["\']'
|
|
347
|
-
matches = re.findall(pattern, text_lower)
|
|
348
|
-
if matches:
|
|
349
|
-
found.append((field, matches))
|
|
350
|
-
|
|
351
|
-
return found
|
|
352
|
-
|
|
353
|
-
def scan_endpoint(self, endpoint, token=None):
|
|
354
|
-
"""
|
|
355
|
-
扫描接口的敏感信息泄露
|
|
356
|
-
"""
|
|
357
|
-
headers = {}
|
|
358
|
-
if token:
|
|
359
|
-
headers['Authorization'] = f'Bearer {token}'
|
|
360
|
-
|
|
361
|
-
resp = requests.get(f"{self.target}/{endpoint}", headers=headers)
|
|
362
|
-
|
|
363
|
-
findings = []
|
|
364
|
-
text = resp.text
|
|
365
|
-
|
|
366
|
-
# 检查禁止字段
|
|
367
|
-
forbidden = self.check_forbidden_fields(text)
|
|
368
|
-
if forbidden:
|
|
369
|
-
findings.append(('禁止字段泄露', forbidden))
|
|
370
|
-
|
|
371
|
-
# 检查脱敏
|
|
372
|
-
phone_status, phone_msg = self.check_masking(text, 'phone')
|
|
373
|
-
if not phone_status:
|
|
374
|
-
findings.append(('手机号未脱敏', phone_msg))
|
|
375
|
-
|
|
376
|
-
idcard_status, idcard_msg = self.check_masking(text, 'idcard')
|
|
377
|
-
if not idcard_status:
|
|
378
|
-
findings.append(('身份证未脱敏', idcard_msg))
|
|
379
|
-
|
|
380
|
-
return {
|
|
381
|
-
'endpoint': endpoint,
|
|
382
|
-
'status_code': resp.status_code,
|
|
383
|
-
'findings': findings,
|
|
384
|
-
'is_sensitive': len(findings) > 0
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
def run_tests(self, endpoints, token=None):
|
|
388
|
-
"""批量测试敏感信息泄露"""
|
|
389
|
-
print(f"\n=== 敏感信息泄露测试 ===\n")
|
|
390
|
-
|
|
391
|
-
results = []
|
|
392
|
-
for endpoint in endpoints:
|
|
393
|
-
result = self.scan_endpoint(endpoint, token)
|
|
394
|
-
results.append(result)
|
|
395
|
-
|
|
396
|
-
status = "⚠️ 发现问题" if result['is_sensitive'] else "✅ 安全"
|
|
397
|
-
print(f"[{status}] {endpoint}")
|
|
398
|
-
for finding_type, details in result['findings']:
|
|
399
|
-
print(f" - {finding_type}: {details}")
|
|
400
|
-
|
|
401
|
-
return results
|
|
402
|
-
|
|
403
|
-
# 使用示例
|
|
404
|
-
if __name__ == "__main__":
|
|
405
|
-
tester = SensitiveDataTester("http://api")
|
|
406
|
-
|
|
407
|
-
# 测试不需要认证的接口
|
|
408
|
-
public_endpoints = ['/user/info', '/product/list', '/news']
|
|
409
|
-
tester.run_tests(public_endpoints)
|
|
410
|
-
|
|
411
|
-
# 测试需要认证的接口
|
|
412
|
-
private_endpoints = ['/user/info', '/order/list']
|
|
413
|
-
tester.run_tests(private_endpoints, token="user_token")
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
## 10. 实战判断案例
|
|
417
|
-
|
|
418
|
-
### 案例1:登录响应返回token是正常的
|
|
419
|
-
|
|
420
|
-
```
|
|
421
|
-
【场景】:登录接口返回token
|
|
422
|
-
|
|
423
|
-
curl测试:
|
|
424
|
-
curl -X POST /api/login -d '{"username":"admin","password":"xxx"}'
|
|
425
|
-
→ {"code":0,"msg":"登录成功","token":"eyJhbGci..."}
|
|
426
|
-
|
|
427
|
-
判断:
|
|
428
|
-
- 登录接口返回token是正常功能
|
|
429
|
-
- 不是敏感信息泄露漏洞
|
|
430
|
-
- 结论:【正常】不需要修复
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
### 案例2:用户信息包含password是漏洞
|
|
434
|
-
|
|
435
|
-
```
|
|
436
|
-
【场景】:用户信息接口返回password字段
|
|
437
|
-
|
|
438
|
-
curl测试:
|
|
439
|
-
curl -H "Authorization: Bearer $TOKEN" /api/user/info
|
|
440
|
-
→ {"userId":1,"username":"admin","password":"明文密码123"}
|
|
441
|
-
|
|
442
|
-
判断:
|
|
443
|
-
- 响应包含password字段
|
|
444
|
-
- password不应返回前端
|
|
445
|
-
- 结论:【确认漏洞】密码明文泄露
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
### 案例3:手机号未脱敏是漏洞
|
|
449
|
-
|
|
450
|
-
```
|
|
451
|
-
【场景】:接口返回未脱敏的手机号
|
|
452
|
-
|
|
453
|
-
curl测试:
|
|
454
|
-
# 场景1:公开接口
|
|
455
|
-
curl /api/user/list
|
|
456
|
-
→ [{"name":"张三","phone":"13800138000"}]
|
|
457
|
-
|
|
458
|
-
# 场景2:个人中心
|
|
459
|
-
curl -H "Authorization: Bearer $TOKEN" /api/user/info
|
|
460
|
-
→ {"name":"张三","phone":"13800138000"}
|
|
461
|
-
|
|
462
|
-
判断:
|
|
463
|
-
- 场景1:公开接口返回未脱敏手机号 → 漏洞
|
|
464
|
-
- 场景2:个人中心返回未脱敏手机号 → 可能漏洞(取决于业务需求)
|
|
465
|
-
- 结论:【需确认】建议脱敏处理
|
|
466
|
-
```
|