@comate/zulu 1.4.0-beta.4 → 1.4.0-beta.6
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/comate-engine/assets/skills/auto-commit/SKILL.md +2 -0
- package/comate-engine/assets/skills/auto-commit-sandbox-comate/SKILL.md +2 -2
- package/comate-engine/assets/skills/code-review/SKILL.md +6 -5
- package/comate-engine/assets/skills/code-review/agents/custom-reviewer.md +2 -2
- package/comate-engine/assets/skills/code-review/agents/meta-reviewer.md +2 -2
- package/comate-engine/assets/skills/code-review/agents/style-reviewer.md +72 -10
- package/comate-engine/assets/skills/code-review/references/dispatch-template.md +12 -12
- package/comate-engine/assets/skills/code-review/references/rules/Java/JAVA_STYLE_RULES.md +11 -5
- package/comate-engine/assets/skills/code-security/SKILL.md +110 -41
- package/comate-engine/assets/skills/code-security/references/credential_hosting.md +190 -28
- package/comate-engine/assets/skills/code-security/references/vul_analysis-go_sql_injection.md +149 -0
- package/comate-engine/assets/skills/code-security/references/vul_analysis-java_sql_injection.md +185 -0
- package/comate-engine/assets/skills/code-security/references/vul_analysis-php_sql_injection.md +147 -0
- package/comate-engine/assets/skills/code-security/references/vul_analysis-python_sql_injection.md +143 -0
- package/comate-engine/assets/skills/code-security/references/vul_repair-go_sql_injection.md +2 -2
- package/comate-engine/assets/skills/code-security/references/vul_repair-sca.md +225 -0
- package/comate-engine/assets/skills/code-security/scripts/credential_hosting.py +12 -10
- package/comate-engine/assets/skills/code-security/scripts/credential_open_page.py +125 -0
- package/comate-engine/assets/skills/code-security/scripts/credential_poll.py +12 -9
- package/comate-engine/assets/skills/code-security/scripts/credential_url.py +81 -0
- package/comate-engine/assets/skills/code-security/scripts/ducc/get_claude_session_id.sh +33 -0
- package/comate-engine/assets/skills/code-security/scripts/ducc/open_browser.py +191 -0
- package/comate-engine/assets/skills/code-security/scripts/parse_scan_result.py +99 -16
- package/comate-engine/assets/skills/code-security/scripts/repair_vulnerability.py +66 -13
- package/comate-engine/assets/skills/code-security/scripts/scan_vulnerability.py +44 -12
- package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/SKILL.md +8 -8
- package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/long_running_task.md +0 -15
- package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/testing_strategy.md +1 -1
- package/comate-engine/assets/skills/create-image/SKILL.md +197 -206
- package/comate-engine/assets/skills/create-image/scripts/generate-image.ps1 +213 -0
- package/comate-engine/assets/skills/create-image/scripts/generate-image.sh +322 -0
- package/comate-engine/assets/skills/create-subagent/SKILL.md +23 -5
- package/comate-engine/fallbackServer.js +1 -1
- package/comate-engine/node_modules/@comate/plugin-shared-internals/dist/index.js +1 -1
- package/comate-engine/server.js +89 -66
- package/dist/bundle/index.js +3 -3
- package/package.json +1 -1
- package/scripts/postinstall.js +4 -3
- package/comate-engine/assets/skills/code-review/evals/SKILL.md +0 -334
- package/comate-engine/assets/skills/code-review/evals/agents/gt-generator.md +0 -76
- package/comate-engine/assets/skills/code-review/evals/agents/miner.md +0 -87
- package/comate-engine/assets/skills/code-review/evals/agents/score-judge.md +0 -168
- package/comate-engine/assets/skills/code-review/evals/references/cli-query-template.md +0 -114
- package/comate-engine/assets/skills/code-review/evals/references/gt-schema.md +0 -77
- package/comate-engine/assets/skills/code-review/references/custom-rules/RULE_TEMPLATE.md +0 -141
- /package/comate-engine/assets/commands/{code-review-comate.md → code-review.md} +0 -0
- /package/comate-engine/assets/commands/{debug-comate.md → debug.md} +0 -0
- /package/comate-engine/assets/commands/{unit-test-comate.md → unit-test.md} +0 -0
- /package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/backend_dev.md +0 -0
- /package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/env_setup.md +0 -0
- /package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/frontend_dev.md +0 -0
- /package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/references/git_operations.md +0 -0
- /package/comate-engine/assets/skills/{create-automation-tasks-comate → create-automation}/scripts/check_config.py +0 -0
package/comate-engine/assets/skills/code-security/references/vul_analysis-php_sql_injection.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# 漏洞复核流程
|
|
2
|
+
|
|
3
|
+
你是一个资深的安全审计专家,请对 PHP 代码的 SQL 注入漏洞扫描结果进行复核,只需要判断是否为误报。
|
|
4
|
+
|
|
5
|
+
漏洞复核可分为三个步骤:
|
|
6
|
+
|
|
7
|
+
1. 数据读取:仔细阅读污点追踪信息(trace)及相关的代码文件。
|
|
8
|
+
2. 漏洞分析:根据「漏洞分析」的要求判断漏洞是否为误报。
|
|
9
|
+
3. 结果输出:按照格式要求输出复核结果。
|
|
10
|
+
|
|
11
|
+
## 数据读取
|
|
12
|
+
|
|
13
|
+
阅读扫描报告 parsed_result.json,其中包含了详细的漏洞位置、数据流信息以及漏洞类型说明。
|
|
14
|
+
|
|
15
|
+
## 漏洞分析
|
|
16
|
+
|
|
17
|
+
### 分析步骤(请严格按顺序执行,满足终止条件时立即停止)
|
|
18
|
+
**Step 1 - 追踪校验逻辑**
|
|
19
|
+
从污点来源到危险函数,逐行检查是否存在对该参数的过滤/校验代码。
|
|
20
|
+
参考「误报特征」中列举的保护类型进行识别。
|
|
21
|
+
**重要**:校验逻辑可能是间接的,以下两种模式都属于有效校验:
|
|
22
|
+
- **字典/数组查找**:如果污点变量被用作数组/字典的 key 来查找值,且查找失败会中断执行,则该查找本身就是对污点变量的白名单校验——因为只有 key 恰好等于白名单中某个固定值时才能继续执行。
|
|
23
|
+
- **参数化查询存在性校验**:如果污点变量通过参数化查询(预编译/ORM)去数据库查询是否存在匹配记录,且查询无结果会中断执行(throw/return/die),则该查询等价于隐式白名单校验。推理链条为:参数化查询本身不会产生 SQL 注入 → 查询要求数据库中存在与污点变量精确匹配的记录 → SQL 注入 payload(如 `' OR 1=1--`)不可能作为合法业务数据存在于数据库中 → payload 无法通过校验 → 后续即使拼接 SQL 也是安全的。**这种模式应判定为 false_positive**。
|
|
24
|
+
|
|
25
|
+
**边界条件**:如果被查询字段是用户可写入的(如 username、title、备注等任意字符串字段)且无字符集限制,攻击者可能预先注册 `admin' OR 1=1--` 这样的合法记录,此时存在性校验不再可靠,**不能据此判定为误报**。仅当被查询字段是系统受控、字符集受限(如纯数字 ID、枚举码、内部字典表)时,该模式才成立。
|
|
26
|
+
|
|
27
|
+
如果 Step 1 未发现任何校验逻辑,跳过 Step 2,直接进入 Step 3。
|
|
28
|
+
|
|
29
|
+
**Step 2 - 验证中断有效性**
|
|
30
|
+
如果 Step 1 发现校验逻辑,检查校验失败时是否会中断后续执行。
|
|
31
|
+
需要找到对应的 exit / die / return / throw 语句(可能在被调用函数内部)。
|
|
32
|
+
**特别注意**:中断判断要考虑间接中断。例如 `$rid = $map[$user_input]; if (empty($rid)) return error;`,校验的是 `$rid`(映射结果)而非 `$user_input`(污点变量本身),但如果 `$user_input` 不在 `$map` 的 key 中则 `$rid` 必为空,从而触发中断——这等价于对 `$user_input` 的白名单校验。同理,参数化查询 `$record = Model::find('col=:col', [':col'=>$input]); if (!$record) throw ...;` 校验的是 `$record`(查询结果),但如果 `$input` 不在数据库中则 `$record` 必为空/null,从而触发中断——这同样等价于对 `$input` 的白名单校验。
|
|
33
|
+
**提前终止决策(Step 2 完成后必须执行)**
|
|
34
|
+
如果同时满足以下两个条件,执行「终止验证」后立即输出结论,**禁止继续分析**:
|
|
35
|
+
- 条件 A:Step 1 发现了覆盖全部污点参数的校验逻辑
|
|
36
|
+
- 条件 B:Step 2 确认校验失败时会中断执行
|
|
37
|
+
|
|
38
|
+
「终止验证」:选取一个 SQL 注入 payload,
|
|
39
|
+
逐步写出代入校验函数的每一步输入和输出值,确认该 payload 确实无法通过校验。
|
|
40
|
+
验证通过后,判定为 **false_positive**,输出结论。
|
|
41
|
+
|
|
42
|
+
**Step 3 - 验证防御有效性**(仅当未触发「提前终止决策」时执行,即条件 A 或条件 B 任一不成立)
|
|
43
|
+
检查通过校验的值,其格式/范围是否能排除 SQL 注入所需的特殊字符(如引号、注释符 `--` 等)。
|
|
44
|
+
|
|
45
|
+
**Step 4 - 覆盖完整性检查**(仅当未触发「提前终止决策」时执行)
|
|
46
|
+
确认保护措施是否覆盖了进入危险函数的所有污点参数,任一参数未被保护则判定为 true_positive。
|
|
47
|
+
|
|
48
|
+
### true_positive 推演示例(参考)
|
|
49
|
+
扫描结果指出某 PHP 文件中如下代码存在 SQL 注入:
|
|
50
|
+
|
|
51
|
+
```php
|
|
52
|
+
public function listOrders() {
|
|
53
|
+
$orderBy = $_GET['order_by'] ?? 'id';
|
|
54
|
+
$sql = "SELECT * FROM orders ORDER BY " . $orderBy;
|
|
55
|
+
return Db::query($sql);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- Step 1:仅有默认值兜底,未发现白名单/类型转换/正则等任何能限定取值范围的逻辑("误报特征注意 #1" 明确空校验不算)。
|
|
60
|
+
- Step 2:跳过(Step 1 未发现校验)。
|
|
61
|
+
- 提前终止决策:条件 A 不成立,不能终止。
|
|
62
|
+
- Step 3:`$orderBy` 直接拼入 SQL 结构(ORDER BY 子句),可包含任意字符(如 `id; DROP TABLE orders--`)。
|
|
63
|
+
- Step 4:唯一污点参数未被保护。
|
|
64
|
+
- 结论:**true_positive**,原因记录为"`order_by` 经默认值兜底后直接拼入 ORDER BY 子句,未做白名单限制,可注入 `id; DROP TABLE orders--` 等 payload"。
|
|
65
|
+
|
|
66
|
+
### 误报判断逻辑
|
|
67
|
+
1. 如果代码中存在有效的过滤、校验、清理逻辑,则为误报 (false_positive),有效的定义是指能够防御当前漏洞场景,具体可参考「误报特征」。
|
|
68
|
+
2. 只要存在能够防御漏洞的代码就算误报,比如强制类型转换、数字类型校验、字符串格式校验等,**不要求一定使用预编译或参数化查询等最佳实践**
|
|
69
|
+
3. 该路径在实际运行中无法触发(如死代码、测试代码等),则为误报 (false_positive)。
|
|
70
|
+
4. 其他的情况,则认为是真实存在的漏洞(true_positive)。
|
|
71
|
+
|
|
72
|
+
### 分析纪律
|
|
73
|
+
|
|
74
|
+
1. **禁止使用未验证假设**:对任何"可能存在绕过"的判断,必须附上具体 payload 代入每一步函数的输入/输出推演过程,否则该判断无效。
|
|
75
|
+
2. **找到误报证据即止步**:完成「终止验证」后,禁止继续寻找理论上的绕过方式。
|
|
76
|
+
3. **摇摆结论以推演为准**:分析过程中如结论出现反复,以最后一次有具体值代入推演支撑的结论为准,无推演支撑的推测性结论一律作废。
|
|
77
|
+
4. **禁止运行代码或编写测试**:但允许查阅 PHP 标准库或第三方库的官方文档以确认函数行为(例如 `intval` 对带特殊字符输入的行为),不得通过实际执行代码来验证。
|
|
78
|
+
5. **证据不足时保守判定**:如果数据流不完整、关键代码缺失(如外部闭源依赖、自定义框架内部行为不明)、无法对所有污点参数进行完整推演,**判定为 true_positive**,并在 `reason` 中说明缺失的证据。误报需要正面证据,而真漏洞是默认假设。
|
|
79
|
+
|
|
80
|
+
### 误报特征
|
|
81
|
+
代码中存在但不局限于以下特征可认为是安全的,可以判定为误报:
|
|
82
|
+
|
|
83
|
+
1. 输入数据在进入危险函数前,经过了强制类型转换,参数被转换为数字类型(如 `intval()`、`(int)$input` 在 PHP 中)。
|
|
84
|
+
2. 输入数据在进入危险函数前,经过了白名单过滤,包括但不限于以下形式:
|
|
85
|
+
- **显式白名单**:`in_array($input, $whitelist)` 或 `array_key_exists($input, $map)` 等直接校验。
|
|
86
|
+
- **隐式白名单(数组/字典等值映射查找)**:污点变量作为 key 去查找固定数组/字典,然后对查找结果做非空校验,失败则中断执行。此时污点变量的值域被限定为数组中的固定 key,不可能包含 SQL 注入 payload。
|
|
87
|
+
```php
|
|
88
|
+
// 典型模式:$input 作为 key 查找固定映射,映射失败则返回/抛出错误
|
|
89
|
+
$result = $fixed_map[$input]; // 隐式白名单:$input 必须是 $fixed_map 的某个固定 key
|
|
90
|
+
if (empty($result)) return error; // 映射失败中断
|
|
91
|
+
// 此处 $input 的值已被限定为 $fixed_map 的 key,是安全的
|
|
92
|
+
do_query("... WHERE col = '$input'");
|
|
93
|
+
```
|
|
94
|
+
- **参数化查询存在性校验**:污点变量通过参数化查询(预编译)去数据库中查询是否存在匹配记录,查询无结果则中断执行。此时污点变量的值被限定为数据库表中已有的合法记录,SQL 注入 payload 不可能作为合法记录存在。
|
|
95
|
+
```php
|
|
96
|
+
// 典型模式:使用参数化查询校验 $input 是否存在于数据库
|
|
97
|
+
$record = Model::model()->find('col=:col', [':col' => $input]);
|
|
98
|
+
if (!$record) {
|
|
99
|
+
throw new Exception('记录不存在'); // 查询无结果则中断
|
|
100
|
+
}
|
|
101
|
+
// 此处 $input 的值已被限定为数据库中已有的合法记录值,是安全的
|
|
102
|
+
do_query("... WHERE col = '$input'");
|
|
103
|
+
```
|
|
104
|
+
- **switch/case 匹配**:`switch($input) { case 'a': ... case 'b': ... default: return error; }` 模式。
|
|
105
|
+
- 上述白名单校验的核心判定标准是:**通过校验后,污点变量的可能取值是否被限定为有限的、已知的安全字符串集合**。
|
|
106
|
+
3. 代码中使用了正则表达式进行输入验证,且表达式能够防御当前场景,比如仅允许数字类型的值。
|
|
107
|
+
4. 输入数据在进入危险函数前,被预编译为安全的代码,比如使用 ORM 框架。
|
|
108
|
+
5. 输入数据经过正则替换清理,如 `preg_replace('/[^a-zA-Z0-9_]/', '', $input)` 且规则可明确排除 SQL 注入所需字符。
|
|
109
|
+
|
|
110
|
+
### 证据优先级(用于减少误判)
|
|
111
|
+
- **强证据**:PDO/mysqli 预编译并使用参数绑定(`prepare + bindValue/bindParam/execute`),且 SQL 结构未由用户输入控制。
|
|
112
|
+
- **中证据**:严格白名单/映射查找并在失败时中断执行。
|
|
113
|
+
- **弱证据**:仅依赖 `addslashes()`、长度限制、宽松正则等**无法完全排除注入风险**的措施。弱证据不能单独判定为 `false_positive`。注:`mysqli_real_escape_string()` 在正确设置字符集且用于字符串值(非 SQL 结构)时属于中证据。
|
|
114
|
+
|
|
115
|
+
### 常见危险反例(命中则倾向 true_positive)
|
|
116
|
+
- 拼接 SQL:`"..." . $input`。
|
|
117
|
+
- 在 `ORDER BY`、列名、表名等 SQL 结构位置使用用户输入。
|
|
118
|
+
- 使用 `query($sql)` 执行动态字符串且未参数绑定。
|
|
119
|
+
|
|
120
|
+
**注意**:
|
|
121
|
+
1. 仅校验参数是否为空(如 `if ($param === null || $param === '')`),没有其他校验逻辑,不能认为是误报。
|
|
122
|
+
2. `htmlspecialchars()` 仅用于 HTML/XSS 编码,不能作为 SQL 注入防护依据。
|
|
123
|
+
|
|
124
|
+
## 结果输出
|
|
125
|
+
|
|
126
|
+
将结果写入到 `analyze_report.json` 文件中,与 `parsed_result.json` 同目录。**输出必须是合法 JSON**(不允许 `//` 注释、不允许末尾逗号),可使用 `python -m json.tool` 自查。
|
|
127
|
+
|
|
128
|
+
字段说明:
|
|
129
|
+
- `vul_hash`:从 `parsed_result.json` 中拷贝的漏洞 hash,用于回写关联。
|
|
130
|
+
- `result`:取值仅限 `"true_positive"` 或 `"false_positive"`。
|
|
131
|
+
- `reason`:判定依据。误报必须给出"起到过滤作用的具体代码 + 推演链条";真漏洞必须给出"可达 payload + 拼接位置"。
|
|
132
|
+
|
|
133
|
+
文件示例(合法 JSON,可直接保存):
|
|
134
|
+
```json
|
|
135
|
+
[
|
|
136
|
+
{
|
|
137
|
+
"vul_hash": "7c3ecd91ff42281bd862b400f5b955b1",
|
|
138
|
+
"result": "false_positive",
|
|
139
|
+
"reason": "代码在第 45 行使用 intval 将 $input 强制转换为 int,转换失败返回 0;payload \"1' OR 1=1--\" 经 intval 返回 1,注入字符已被丢弃。清洗函数:intval"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
"vul_hash": "a1b2c3d4e5f6...",
|
|
143
|
+
"result": "true_positive",
|
|
144
|
+
"reason": "$orderBy 经默认值兜底后直接拼入 ORDER BY 子句(app/Service/OrderService.php:78),可注入 payload \"id; DROP TABLE orders--\",未发现任何白名单/类型转换/参数化保护。"
|
|
145
|
+
}
|
|
146
|
+
]
|
|
147
|
+
```
|
package/comate-engine/assets/skills/code-security/references/vul_analysis-python_sql_injection.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# 漏洞复核流程
|
|
2
|
+
|
|
3
|
+
你是一个资深的安全审计专家,请对 Python 代码的 SQL 注入漏洞扫描结果进行复核,判断是否为误报。
|
|
4
|
+
|
|
5
|
+
漏洞复核可分为三个步骤:
|
|
6
|
+
|
|
7
|
+
1. 数据读取:仔细阅读污点追踪信息(trace)及相关的代码文件。
|
|
8
|
+
2. 漏洞分析:根据「漏洞分析」的要求判断漏洞是否为误报。
|
|
9
|
+
3. 结果输出:按照格式要求输出复核结果。
|
|
10
|
+
|
|
11
|
+
## 数据读取
|
|
12
|
+
|
|
13
|
+
阅读扫描报告 parsed_result.json,其中包含了详细的漏洞位置、数据流信息以及漏洞类型说明。
|
|
14
|
+
|
|
15
|
+
## 漏洞分析
|
|
16
|
+
|
|
17
|
+
### 分析步骤(请严格按顺序执行,满足终止条件时立即停止)
|
|
18
|
+
**Step 1 - 追踪校验逻辑**
|
|
19
|
+
从污点来源到危险函数,逐行检查是否存在对该参数的过滤/校验代码。
|
|
20
|
+
参考「误报特征」中列举的保护类型进行识别。
|
|
21
|
+
**重要**:校验逻辑可能是间接的,以下两种模式都属于有效校验:
|
|
22
|
+
- **字典查找**:如果污点变量被用作字典的 key 来查找值,且查找失败会中断执行,则该查找本身就是对污点变量的白名单校验——因为只有 key 恰好等于白名单中某个固定值时才能继续执行。
|
|
23
|
+
- **参数化查询存在性校验**:如果污点变量通过参数化查询(Django ORM、SQLAlchemy 等)去数据库查询是否存在匹配记录,且查询无结果会中断执行(raise/return),则该查询等价于隐式白名单校验。推理链条为:参数化查询本身不会产生 SQL 注入 → 查询要求数据库中存在与污点变量精确匹配的记录 → SQL 注入 payload(如 `' OR 1=1--`)不可能作为合法业务数据存在于数据库中 → payload 无法通过校验 → 后续即使拼接 SQL 也是安全的。**这种模式应判定为 false_positive**。
|
|
24
|
+
|
|
25
|
+
**边界条件**:如果被查询字段是用户可写入的(如 username、title、备注等任意字符串字段)且无字符集限制,攻击者可能预先注册 `admin' OR 1=1--` 这样的合法记录,此时存在性校验不再可靠,**不能据此判定为误报**。仅当被查询字段是系统受控、字符集受限(如纯数字 ID、枚举码、内部字典表)时,该模式才成立。
|
|
26
|
+
|
|
27
|
+
如果 Step 1 未发现任何校验逻辑,跳过 Step 2,直接进入 Step 3。
|
|
28
|
+
|
|
29
|
+
**Step 2 - 验证中断有效性**
|
|
30
|
+
如果 Step 1 发现校验逻辑,检查校验失败时是否会中断后续执行。
|
|
31
|
+
需要找到对应的 return / raise 语句(可能在被调用函数内部)。
|
|
32
|
+
**特别注意**:中断判断要考虑间接中断。例如 `value = fixed_map.get(user_input); if value is None: raise ValueError()`,校验的是 `value`(映射结果)而非 `user_input`(污点变量本身),但如果 `user_input` 不在 `fixed_map` 的 key 中则 `value` 必为 None,从而触发中断——这等价于对 `user_input` 的白名单校验。同理,`record = Model.objects.filter(name=input).first(); if not record: raise Http404()` 校验的是 `record`(查询结果),但如果 `input` 不在数据库中则 `record` 必为 None,从而触发中断——这同样等价于对 `input` 的白名单校验。
|
|
33
|
+
**提前终止决策(Step 2 完成后必须执行)**
|
|
34
|
+
如果同时满足以下两个条件,执行「终止验证」后立即输出结论,**禁止继续分析**:
|
|
35
|
+
- 条件 A:Step 1 发现了覆盖全部污点参数的校验逻辑
|
|
36
|
+
- 条件 B:Step 2 确认校验失败时会中断执行
|
|
37
|
+
|
|
38
|
+
「终止验证」:选取一个 SQL 注入 payload,
|
|
39
|
+
逐步写出代入校验函数的每一步输入和输出值,确认该 payload 确实无法通过校验。
|
|
40
|
+
验证通过后,判定为 **false_positive**,输出结论。
|
|
41
|
+
|
|
42
|
+
**Step 3 - 验证防御有效性**(仅当未触发「提前终止决策」时执行,即条件 A 或条件 B 任一不成立)
|
|
43
|
+
检查通过校验的值,其格式/范围是否能排除 SQL 注入所需的特殊字符(如引号、注释符 `--` 等)。
|
|
44
|
+
|
|
45
|
+
**Step 4 - 覆盖完整性检查**(仅当未触发「提前终止决策」时执行)
|
|
46
|
+
确认保护措施是否覆盖了进入危险函数的所有污点参数,任一参数未被保护则判定为 true_positive。
|
|
47
|
+
|
|
48
|
+
### true_positive 推演示例(参考)
|
|
49
|
+
扫描结果指出某 Python 文件中如下代码存在 SQL 注入:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
def list_orders():
|
|
53
|
+
order_by = request.args.get('order_by') or 'id'
|
|
54
|
+
sql = f"SELECT * FROM orders ORDER BY {order_by}"
|
|
55
|
+
return cursor.execute(sql).fetchall()
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Step 1:仅有默认值兜底,未发现白名单/类型转换/正则等任何能限定取值范围的逻辑("误报特征注意 #1" 明确空校验不算)。
|
|
59
|
+
- Step 2:跳过(Step 1 未发现校验)。
|
|
60
|
+
- 提前终止决策:条件 A 不成立,不能终止。
|
|
61
|
+
- Step 3:`order_by` 经 f-string 直接拼入 SQL 结构(ORDER BY 子句),可包含任意字符(如 `id; DROP TABLE orders--`)。
|
|
62
|
+
- Step 4:唯一污点参数未被保护。
|
|
63
|
+
- 结论:**true_positive**,原因记录为"`order_by` 经默认值兜底后通过 f-string 拼入 ORDER BY 子句,未做白名单限制,可注入 `id; DROP TABLE orders--` 等 payload"。
|
|
64
|
+
|
|
65
|
+
### 误报判断逻辑
|
|
66
|
+
1. 如果代码中存在有效的过滤、校验、清理逻辑,则为误报 (false_positive),有效的定义是指能够防御当前漏洞场景,具体可参考「误报特征」。
|
|
67
|
+
2. 只要存在能够防御漏洞的代码就算误报,比如强制类型转换、数字类型校验、字符串格式校验等,**不要求一定使用预编译或参数化查询等最佳实践**
|
|
68
|
+
3. 该路径在实际运行中无法触发(如死代码、测试代码等),则为误报 (false_positive)。
|
|
69
|
+
4. 其他的情况,则认为是真实存在的漏洞(true_positive)。
|
|
70
|
+
|
|
71
|
+
### 分析纪律
|
|
72
|
+
|
|
73
|
+
1. **禁止使用未验证假设**:对任何"可能存在绕过"的判断,必须附上具体 payload 代入每一步函数的输入/输出推演过程,否则该判断无效。
|
|
74
|
+
2. **找到误报证据即止步**:完成「终止验证」后,禁止继续寻找理论上的绕过方式。
|
|
75
|
+
3. **摇摆结论以推演为准**:分析过程中如结论出现反复,以最后一次有具体值代入推演支撑的结论为准,无推演支撑的推测性结论一律作废。
|
|
76
|
+
4. **禁止运行代码或编写测试**:但允许查阅 Python 标准库或第三方库的官方文档以确认函数行为(例如 `int()` 对带特殊字符输入的行为),不得通过实际执行代码来验证。
|
|
77
|
+
5. **证据不足时保守判定**:如果数据流不完整、关键代码缺失(如外部闭源依赖、自定义 ORM 内部行为不明)、无法对所有污点参数进行完整推演,**判定为 true_positive**,并在 `reason` 中说明缺失的证据。误报需要正面证据,而真漏洞是默认假设。
|
|
78
|
+
|
|
79
|
+
### 误报特征
|
|
80
|
+
代码中存在以下特征可认为是安全的,可以判定为误报:
|
|
81
|
+
|
|
82
|
+
1. 输入数据在进入危险函数前,经过了强制类型转换,参数被转换为数字类型(如 `int()`、`float()`,或 `Decimal` 后再做范围校验)。
|
|
83
|
+
2. 输入数据在进入危险函数前,经过了白名单过滤,包括但不限于以下形式:
|
|
84
|
+
- **显式白名单**:`input in whitelist` 或 `input in dict_map` 等直接校验。
|
|
85
|
+
- **隐式白名单(字典/列表等值映射查找)**:污点变量作为 key 去查找固定字典,然后对查找结果做非空校验,失败则中断执行。此时污点变量的值域被限定为字典中的固定 key,不可能包含 SQL 注入 payload。
|
|
86
|
+
```python
|
|
87
|
+
# 典型模式:input 作为 key 查找固定字典,映射失败则抛出异常
|
|
88
|
+
value = fixed_map.get(input)
|
|
89
|
+
if value is None:
|
|
90
|
+
raise ValueError("invalid input")
|
|
91
|
+
# 此处 input 的值已被限定为 fixed_map 的 key,是安全的
|
|
92
|
+
cursor.execute("... WHERE col = '%s'" % input)
|
|
93
|
+
```
|
|
94
|
+
- **参数化查询存在性校验**:污点变量通过参数化查询(ORM)去数据库中查询是否存在匹配记录,查询无结果则中断执行。此时污点变量的值被限定为数据库表中已有的合法记录,SQL 注入 payload 不可能作为合法记录存在。
|
|
95
|
+
```python
|
|
96
|
+
# 典型模式:使用 ORM 参数化查询校验 input 是否存在于数据库
|
|
97
|
+
record = Model.objects.filter(name=input).first()
|
|
98
|
+
if not record:
|
|
99
|
+
raise Http404("记录不存在")
|
|
100
|
+
# 此处 input 的值已被限定为数据库中已有的合法记录值,是安全的
|
|
101
|
+
```
|
|
102
|
+
- **if/elif 链或字典映射**:类似 switch/case 的等值匹配模式,default 分支中断执行。
|
|
103
|
+
- 上述白名单校验的核心判定标准是:**通过校验后,污点变量的可能取值是否被限定为有限的、已知的安全字符串集合**。
|
|
104
|
+
3. 代码中使用了正则表达式进行输入验证,且表达式能够防御当前场景,比如仅允许数字类型的值。
|
|
105
|
+
4. 输入数据在进入危险函数前,被预编译为安全的代码,比如使用 ORM 框架或 DB-API 参数绑定。
|
|
106
|
+
|
|
107
|
+
### 证据优先级(用于减少误判)
|
|
108
|
+
- **强证据**:参数化查询(`cursor.execute(sql, params)`、ORM filter 绑定参数)且未拼接用户输入到 SQL 结构。
|
|
109
|
+
- **中证据**:严格白名单/字典映射查找并在失败时中断执行。
|
|
110
|
+
- **弱证据**:仅依赖 `replace` 清理、长度限制、宽松正则。弱证据不能单独判定为 `false_positive`。
|
|
111
|
+
|
|
112
|
+
### 常见危险反例(命中则倾向 true_positive)
|
|
113
|
+
- 使用 f-string、`%`、`.format()` 拼接 SQL。
|
|
114
|
+
- 在 `order by`、列名、表名等 SQL 结构位置使用用户输入。
|
|
115
|
+
- `cursor.execute(dynamic_sql)` 执行动态拼接 SQL 且无参数绑定。
|
|
116
|
+
|
|
117
|
+
**注意**:
|
|
118
|
+
1. 仅校验参数是否为空(如 `if param is None` 或 `if not param`),没有其他校验逻辑,不能认为是误报。
|
|
119
|
+
|
|
120
|
+
## 结果输出
|
|
121
|
+
|
|
122
|
+
将结果写入到 `analyze_report.json` 文件中,与 `parsed_result.json` 同目录。**输出必须是合法 JSON**(不允许 `//` 注释、不允许末尾逗号),可使用 `python -m json.tool` 自查。
|
|
123
|
+
|
|
124
|
+
字段说明:
|
|
125
|
+
- `vul_hash`:从 `parsed_result.json` 中拷贝的漏洞 hash,用于回写关联。
|
|
126
|
+
- `result`:取值仅限 `"true_positive"` 或 `"false_positive"`。
|
|
127
|
+
- `reason`:判定依据。误报必须给出"起到过滤作用的具体代码 + 推演链条";真漏洞必须给出"可达 payload + 拼接位置"。
|
|
128
|
+
|
|
129
|
+
文件示例(合法 JSON,可直接保存):
|
|
130
|
+
```json
|
|
131
|
+
[
|
|
132
|
+
{
|
|
133
|
+
"vul_hash": "7c3ecd91ff42281bd862b400f5b955b1",
|
|
134
|
+
"result": "false_positive",
|
|
135
|
+
"reason": "代码在第 45 行使用 int() 将 input 强制转换为整数,转换失败抛 ValueError;payload \"1' OR 1=1--\" 经 int() 抛异常,无法到达 cursor.execute。清洗函数:int"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"vul_hash": "a1b2c3d4e5f6...",
|
|
139
|
+
"result": "true_positive",
|
|
140
|
+
"reason": "order_by 参数经默认值兜底后通过 f-string 拼入 ORDER BY 子句(app/services/order_service.py:78),可注入 payload \"id; DROP TABLE orders--\",未发现任何白名单/类型转换/参数化保护。"
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
```
|
|
@@ -9,7 +9,7 @@ go sqli 漏洞修复知识
|
|
|
9
9
|
2. 污点数据拼接到 sql 语句时,是作为 sql 语句中 select、update、delete 等子句,且无法确定子句具体信息,也是不可修复场景,不进行漏洞修复。
|
|
10
10
|
|
|
11
11
|
### 可修复场景
|
|
12
|
-
1. 漏洞修复必须在 **SQL
|
|
12
|
+
1. 漏洞修复必须在 **SQL 语句生成 或者 SQL 语句执行所在的文件和函数内以及数据流传递链路所在文件**完成,不要创建新的代码文件。
|
|
13
13
|
2. 同个文件进行参数过滤时,可以在文件头定义过滤正则,如果定义已经存在,可以直接复用。
|
|
14
14
|
3. 对于 where 列名(操作符)之后的 value、insert 的values、like 的 value,需要使用**预编译/参数绑定**的方式进行漏洞修复。**注意**:LIKE 子句的值虽然可以预编译,但 `%` 和 `_` 是 SQL 通配符,若用户输入包含这些字符可能导致非预期的模糊匹配。如需精确匹配,应先转义这些字符:
|
|
15
15
|
|
|
@@ -1018,4 +1018,4 @@ Beego ORM同样存在直接拼接SQL导致注入的风险。
|
|
|
1018
1018
|
// 安全: 使用参数化查询
|
|
1019
1019
|
o.Raw("SELECT * FROM users WHERE username = ?", username).QueryRow(&user)
|
|
1020
1020
|
```
|
|
1021
|
-
##
|
|
1021
|
+
##
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
SCA(软件成分分析)漏洞修复知识
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
SCA 类漏洞不是源码层面的代码缺陷,而是项目依赖了存在已知漏洞(CVE / 内部安全公告)的第三方组件。修复方式是 **升级依赖包到安全版本**,一般不需要改动业务源码。本文档只覆盖 **Go 和 Java** 两种生态。
|
|
6
|
+
|
|
7
|
+
## 核心原则
|
|
8
|
+
|
|
9
|
+
1. **只改依赖清单文件,不要改业务源码**。SCA 修复的本质是换版本,业务代码不应被触碰。
|
|
10
|
+
2. **必须升到扫描结果里标注的 "安全版本" 或更高**,不能升到更低的补丁版本,否则复测仍会命中。
|
|
11
|
+
3. **保持其他依赖不变**,只修改受影响的那一行,避免连锁破坏构建。
|
|
12
|
+
4. **版本号格式必须符合该包管理器的约定**(Go 的 `v` 前缀、Maven 的 `<version>` 等),不要随意改变版本声明风格。
|
|
13
|
+
|
|
14
|
+
## 从 `scan_result.json` 提取修复信息
|
|
15
|
+
|
|
16
|
+
对于 SCA 类漏洞,`scan_result.json`(或解析出的 `parsed_result.json`)里通常包含以下关键字段(位置见 SARIF 的 `results[].properties` 或 `rules[]`):
|
|
17
|
+
|
|
18
|
+
| 字段 | 用途 |
|
|
19
|
+
|------|------|
|
|
20
|
+
| `importPath` | 漏洞组件的**引入路径 / 包名**(如 `github.com/baidubce/bce-sdk-go` 或 `org.apache.logging.log4j:log4j-core`)。如果为空字符串,说明该条结果不是 SCA 场景,应按源码类漏洞处理。 |
|
|
21
|
+
| `description` / `suggestion` | 通常会写明受影响版本区间和建议升级到的安全版本(例如 "v0.9.263 及之前版本存在漏洞,升级到 v0.9.264 及以上版本")。 |
|
|
22
|
+
| `file` / `startLine` | 指向依赖声明所在的文件和行,一般就是 `go.mod`、`pom.xml`、`build.gradle` 等。 |
|
|
23
|
+
|
|
24
|
+
**提取步骤**:
|
|
25
|
+
1. 读取漏洞条目,取 `importPath` 作为待升级组件标识。
|
|
26
|
+
2. 从 `description`、`suggestion`、`message` 中解析出安全版本号(关键词:安全版本 / 修复版本 / fixed in / upgrade to / >=)。若文本里同时出现"受影响版本上限"和"建议版本",以**建议/安全版本**为准。
|
|
27
|
+
3. 定位 `file` 指向的依赖清单文件中对应 `importPath` 的那一行。
|
|
28
|
+
|
|
29
|
+
## 修复模式
|
|
30
|
+
|
|
31
|
+
### Go (`go.mod`)
|
|
32
|
+
|
|
33
|
+
#### 情况 1:漏洞组件是直接依赖,`go.mod` 里有对应行
|
|
34
|
+
|
|
35
|
+
**修复前**:
|
|
36
|
+
```go
|
|
37
|
+
require (
|
|
38
|
+
github.com/baidubce/bce-sdk-go v0.9.263
|
|
39
|
+
github.com/gin-gonic/gin v1.9.1
|
|
40
|
+
)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**修复后**(升级到安全版本 `v0.9.264` 或更高):
|
|
44
|
+
```go
|
|
45
|
+
require (
|
|
46
|
+
github.com/baidubce/bce-sdk-go v0.9.266
|
|
47
|
+
github.com/gin-gonic/gin v1.9.1
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
要点:
|
|
52
|
+
- 只替换匹配 `importPath` 的那一行,保留空行/缩进/其他依赖顺序。
|
|
53
|
+
- `v` 前缀不能省略。
|
|
54
|
+
- 如果该组件同时出现在 `require (...)` 块和 `// indirect` 块里,两处都要改成同一版本。
|
|
55
|
+
- `go.sum` 会在构建 / `go mod tidy` 时自动刷新,**本次修复不需要手动修改 `go.sum`**。
|
|
56
|
+
|
|
57
|
+
#### 情况 2:漏洞组件是间接依赖,`go.mod` 里没有对应行
|
|
58
|
+
|
|
59
|
+
出现条件:
|
|
60
|
+
- 漏洞组件 C 没被你的源码直接 `import`;
|
|
61
|
+
- `go.mod` 里也没有 `C ... // indirect`(因为上游直接依赖 B 的 `go.mod` 递归就能推导出 C 的当前版本,Go 不会重复写);
|
|
62
|
+
- 又不能/不想升级 B(B 尚未发布含安全 C 的新版,或升 B 会引入破坏性变更)。
|
|
63
|
+
|
|
64
|
+
此时通过**新增一条 `// indirect`** 把 C 钉到安全版本。推荐用命令,不手改:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
go get github.com/xxx/C@v1.3.0 # v1.3.0 为安全版本
|
|
68
|
+
go mod tidy # 自动补 // indirect 注释、刷新 go.sum
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
效果等同于 `go.mod` 多出:
|
|
72
|
+
|
|
73
|
+
```go
|
|
74
|
+
require (
|
|
75
|
+
github.com/xxx/C v1.3.0 // indirect
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
原理:MVS(Minimum Version Selection)取依赖图中该模块被要求过的**最大版本**。你手动声明的 `v1.3.0` 参与这次选择,且优先级不低于上游,于是最终选中 ≥ 安全版本的 C。
|
|
80
|
+
|
|
81
|
+
必须核查的前置条件:
|
|
82
|
+
1. **同一个 major 版本**。`v2+` 在 Go modules 中是**不同的模块路径**(`github.com/xxx/C/v2`),不能靠 MVS 自动升上去。若安全版本跨了 major,只能换上游依赖或自己 fork。
|
|
83
|
+
2. **上游没有更高下限**。如果 B 的 `go.mod` 里写的是 `require C v1.4.0`,你钉 `v1.3.0` 无效,MVS 会选 `v1.4.0`;此时要钉到 `≥ v1.4.0 且 ≥ 安全版本`。
|
|
84
|
+
3. **钉版本必须与 B 依赖的 C 保持 API 兼容**(同 major 号按语义化版本应兼容)。不兼容时上层代码会编译失败,需要改 B 或放弃此方案。
|
|
85
|
+
|
|
86
|
+
修复后必须验证:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
go mod why github.com/xxx/C # 确认 C 仍在依赖图里
|
|
90
|
+
go list -m github.com/xxx/C # 打印最终选中版本,必须 ≥ 安全版本
|
|
91
|
+
go build ./... # 构建通过
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
注意事项:
|
|
95
|
+
- 间接依赖钉版本是**临时方案**,会带来后续维护成本(上游 B 升级时可能冲突)。长期建议推动 B 升级或自行 fork。
|
|
96
|
+
- 不要只在 `go.mod` 手写一行 `// indirect` 而不跑 `go mod tidy`,这会让 `go.sum` 缺失校验信息,CI 构建会失败。
|
|
97
|
+
|
|
98
|
+
### Java (Maven `pom.xml` / Gradle `build.gradle`)
|
|
99
|
+
|
|
100
|
+
Java 的 `importPath` 通常形如 `groupId:artifactId`,例如 `org.apache.logging.log4j:log4j-core`。
|
|
101
|
+
|
|
102
|
+
#### 情况 1:漏洞组件是直接依赖
|
|
103
|
+
|
|
104
|
+
**Maven**:
|
|
105
|
+
```xml
|
|
106
|
+
<dependency>
|
|
107
|
+
<groupId>org.apache.logging.log4j</groupId>
|
|
108
|
+
<artifactId>log4j-core</artifactId>
|
|
109
|
+
<version>2.17.1</version>
|
|
110
|
+
</dependency>
|
|
111
|
+
```
|
|
112
|
+
只替换 `<version>` 标签内的版本号。如果版本号通过 `<properties>` 变量引用(`${log4j.version}`),则改 `<properties>` 里的对应条目,不要在使用处硬改。
|
|
113
|
+
|
|
114
|
+
**Gradle**:
|
|
115
|
+
```groovy
|
|
116
|
+
implementation "org.apache.logging.log4j:log4j-core:2.17.1"
|
|
117
|
+
```
|
|
118
|
+
替换冒号后第三段版本号即可。若版本通过 `ext` 变量定义,则改 `ext` 源头。
|
|
119
|
+
|
|
120
|
+
#### 情况 2:漏洞组件是间接依赖(由某个直接依赖 B 传递引入)
|
|
121
|
+
|
|
122
|
+
与 Go 的 MVS 不同,**Maven 默认使用"最近原则"(nearest-wins)**:依赖树中路径最短的声明优先。因此单纯在 `pom.xml` 里加一条高版本 `<dependency>` 通常可以覆盖掉 B 带来的旧版,但更稳妥、更符合主流实践的做法是 **先 `<exclusions>` 排除掉 B 里的旧版,再显式引入新版本**。这样依赖图干净,不会出现同一个 jar 被两次引入导致的 warning,也能抵御"路径变化导致覆盖失效"的问题。
|
|
123
|
+
|
|
124
|
+
##### Maven:排除 + 引入新版本
|
|
125
|
+
|
|
126
|
+
漏洞组件:`com.fasterxml.jackson.core:jackson-databind`,由直接依赖 `B` 间接引入,安全版本 `2.15.4`。
|
|
127
|
+
|
|
128
|
+
修复前(只有对 B 的声明,jackson-databind 间接引入的是旧版):
|
|
129
|
+
```xml
|
|
130
|
+
<dependencies>
|
|
131
|
+
<dependency>
|
|
132
|
+
<groupId>com.example</groupId>
|
|
133
|
+
<artifactId>B</artifactId>
|
|
134
|
+
<version>1.0.0</version>
|
|
135
|
+
</dependency>
|
|
136
|
+
</dependencies>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
修复后:
|
|
140
|
+
```xml
|
|
141
|
+
<dependencies>
|
|
142
|
+
<dependency>
|
|
143
|
+
<groupId>com.example</groupId>
|
|
144
|
+
<artifactId>B</artifactId>
|
|
145
|
+
<version>1.0.0</version>
|
|
146
|
+
<!-- 从 B 的依赖传递里排除旧版 jackson-databind -->
|
|
147
|
+
<exclusions>
|
|
148
|
+
<exclusion>
|
|
149
|
+
<groupId>com.fasterxml.jackson.core</groupId>
|
|
150
|
+
<artifactId>jackson-databind</artifactId>
|
|
151
|
+
</exclusion>
|
|
152
|
+
</exclusions>
|
|
153
|
+
</dependency>
|
|
154
|
+
|
|
155
|
+
<!-- 显式引入安全版本 -->
|
|
156
|
+
<dependency>
|
|
157
|
+
<groupId>com.fasterxml.jackson.core</groupId>
|
|
158
|
+
<artifactId>jackson-databind</artifactId>
|
|
159
|
+
<version>2.15.4</version>
|
|
160
|
+
</dependency>
|
|
161
|
+
</dependencies>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
要点:
|
|
165
|
+
- `<exclusions>` 放在**传递来源 B** 的 `<dependency>` 内部,不是放在 jackson-databind 自身那条。
|
|
166
|
+
- `<exclusion>` 里**只写 `groupId` 和 `artifactId`,不写 `<version>`**(Maven 语法要求)。
|
|
167
|
+
- 如果漏洞组件由多条路径同时传递进来(多个直接依赖都间接用了它),需要在**每一个**直接依赖的 `<dependency>` 里都加 `<exclusions>`,否则任何一条没排除的路径都可能拉回旧版。
|
|
168
|
+
- 排除之后务必新增一条显式的 `<dependency>` 指向安全版本,否则应用会因缺少 jackson-databind 编译/运行失败。
|
|
169
|
+
- 使用 `dependencyManagement` 统一管理版本的项目,可以把安全版本加到 `<dependencyManagement>` 里,然后 `<dependency>` 不写版本;但 `<exclusions>` 仍然要写在 B 的声明里。
|
|
170
|
+
|
|
171
|
+
##### Gradle:排除 + 引入新版本
|
|
172
|
+
|
|
173
|
+
```groovy
|
|
174
|
+
dependencies {
|
|
175
|
+
implementation("com.example:B:1.0.0") {
|
|
176
|
+
exclude group: "com.fasterxml.jackson.core", module: "jackson-databind"
|
|
177
|
+
}
|
|
178
|
+
implementation "com.fasterxml.jackson.core:jackson-databind:2.15.4"
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
要点:
|
|
183
|
+
- `exclude` 在 B 的 `implementation(...)` 闭包里;
|
|
184
|
+
- 若多个直接依赖都传递了旧版 jackson-databind,每个都要加 `exclude`;
|
|
185
|
+
- Gradle 也支持用 `resolutionStrategy.force` 或 `constraints` 强制版本,但排除 + 显式引入的语义更清晰,推荐作为首选。
|
|
186
|
+
|
|
187
|
+
##### 如何确认排除是否生效
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# Maven
|
|
191
|
+
mvn dependency:tree -Dincludes=com.fasterxml.jackson.core:jackson-databind
|
|
192
|
+
|
|
193
|
+
# Gradle
|
|
194
|
+
./gradlew dependencies --configuration runtimeClasspath | grep jackson-databind
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
输出中应只剩你显式声明的安全版本,且不再出现从 B 传递来的旧版行(通常行尾会打 `(*)` 或 `omitted for conflict` 标记)。
|
|
198
|
+
|
|
199
|
+
注意事项:
|
|
200
|
+
- 同样需要确认安全版本与 B 内部使用 jackson-databind 的代码 **API 兼容**(Jackson 大多数 2.x 版本之间兼容,但个别版本移除了类/方法)。不兼容时要权衡改 B 或 fork。
|
|
201
|
+
- `<exclusions>` 是长期解决方案,比 Go 的 indirect 钉版本稳定;但同样建议推动上游 B 升级以减少维护开销。
|
|
202
|
+
|
|
203
|
+
## 修复流程清单
|
|
204
|
+
|
|
205
|
+
1. 从 `parsed_result.json` 的漏洞条目里拿到 `importPath`(组件名)、`file`(依赖文件)、`description` / `suggestion`(包含安全版本)。
|
|
206
|
+
2. 从描述文本里解析出**安全版本**:优先匹配 "升级到 X 及以上"、"fixed in X"、"safe version X"、">= X"。
|
|
207
|
+
3. Read 对应依赖文件,定位到包含 `importPath` 的那一行;找不到 → 属于间接依赖,走对应语言的"情况 2"路径。
|
|
208
|
+
4. 按语言和情况执行替换/新增:
|
|
209
|
+
- Go 直接依赖:改 `go.mod` 里的版本号;
|
|
210
|
+
- Go 间接且无行:`go get pkg@安全版本 && go mod tidy`;
|
|
211
|
+
- Java 直接依赖:改 `<version>` / Gradle 版本串;
|
|
212
|
+
- Java 间接依赖:在传递来源的 `<dependency>` 里加 `<exclusions>`,并新增安全版本的 `<dependency>`。
|
|
213
|
+
5. 如果该组件在同一个文件中出现多次(如 Go 的 `require` + `indirect`,Java 多个直接依赖都传递了同一个间接依赖),全部处理一致。
|
|
214
|
+
6. 不要新增、删除任何其他依赖,也不要对业务源码做改动。
|
|
215
|
+
7. 修复完成后继续走复测扫描流程。
|
|
216
|
+
|
|
217
|
+
## 常见坑
|
|
218
|
+
|
|
219
|
+
- **升错方向**:安全版本通常**大于**受影响版本上限,不要把版本降到"受影响范围以下",因为旧补丁可能仍有别的 CVE。
|
|
220
|
+
- **Go 只改了 `require` 没改 `indirect`**:如果项目直接没依赖该组件、只在 `indirect` 中出现,建议改 `indirect` 行;或通过 `go get` 让它成为新的 indirect 条目,避免被间接依赖拉回旧版本。
|
|
221
|
+
- **Java 只 exclude 没引入新版本**:排除之后如果没新增安全版本的 `<dependency>`,运行时会 `ClassNotFoundException`。两步必须都做。
|
|
222
|
+
- **Java 只改一条路径的 exclude**:多条传递路径时,漏掉的那条会把旧版拉回来,`mvn dependency:tree` 可以定位哪些路径需要补排除。
|
|
223
|
+
- **锁文件/校验文件未刷新**:`go.sum`、`poetry.lock` 等在下次构建时会自动更新,修复脚本不要手动改这些文件。
|
|
224
|
+
- **版本号写成字符串被引用**:`pom.xml` 使用 `<properties>`、`build.gradle` 使用 `ext` 定义版本时,必须改源头定义处,不要在使用处硬改版本。
|
|
225
|
+
- **多个依赖文件**:monorepo 或多模块项目中,同一组件可能在多个 `go.mod` / `pom.xml` 中出现。仅修复扫描结果 `file` 指向的那一个文件即可,不要主动扩散修改。
|
|
@@ -12,19 +12,23 @@
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import argparse
|
|
15
|
+
from utils import make_user_id, HOST, build_headers
|
|
15
16
|
import json
|
|
16
17
|
import logging
|
|
17
18
|
import sys
|
|
19
|
+
import uuid
|
|
18
20
|
|
|
19
21
|
import http_client # noqa: F401 (triggers shared logging config)
|
|
20
|
-
|
|
22
|
+
|
|
23
|
+
USER_ID = ""
|
|
24
|
+
USERNAME = ""
|
|
21
25
|
|
|
22
26
|
logger = logging.getLogger("credential_hosting")
|
|
23
27
|
|
|
24
28
|
|
|
25
|
-
def hosting_credentials(chat_id, platform, credentials
|
|
29
|
+
def hosting_credentials(chat_id, platform, credentials):
|
|
26
30
|
"""将凭证托管到指定平台。"""
|
|
27
|
-
url = "{}/api/v1/deployments/{}/credentials".format(
|
|
31
|
+
url = "{}/api/v1/deployments/{}/credentials".format(HOST, platform)
|
|
28
32
|
payload = {
|
|
29
33
|
"configs": credentials,
|
|
30
34
|
"scanChatID": chat_id,
|
|
@@ -33,14 +37,11 @@ def hosting_credentials(chat_id, platform, credentials, username, user_id):
|
|
|
33
37
|
logger.info("credential_hosting: chat_id=%s, platform=%s, credentials_count=%d",
|
|
34
38
|
chat_id, platform, len(credentials))
|
|
35
39
|
print("正在托管凭证到 {} 平台...".format(platform), file=sys.stderr)
|
|
36
|
-
return http_client.post(
|
|
37
|
-
url,
|
|
38
|
-
headers=utils.build_headers(username, user_id, chat_id),
|
|
39
|
-
json_body=payload,
|
|
40
|
-
)
|
|
40
|
+
return http_client.post(url, headers=build_headers(USERNAME, USER_ID, chat_id), json_body=payload)
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def main():
|
|
44
|
+
global USER_ID, USERNAME
|
|
44
45
|
parser = argparse.ArgumentParser(description="凭证托管工具")
|
|
45
46
|
parser.add_argument("--poll-result", default=None, help="credential_poll.py 输出的结果文件路径,自动提取所需参数")
|
|
46
47
|
parser.add_argument("--chat-id", default=None, help="scanChatID(使用 --poll-result 时可省略)")
|
|
@@ -49,7 +50,8 @@ def main():
|
|
|
49
50
|
parser.add_argument("--credentials", default=None, help="凭证配置 JSON(使用 --poll-result 时可省略)")
|
|
50
51
|
args = parser.parse_args()
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
USERNAME = args.username
|
|
54
|
+
USER_ID = make_user_id(args.username)
|
|
53
55
|
|
|
54
56
|
chat_id = args.chat_id
|
|
55
57
|
platform = args.platform
|
|
@@ -79,7 +81,7 @@ def main():
|
|
|
79
81
|
print("错误: 缺少必要参数。使用 --poll-result 或同时提供 --chat-id、--platform、--credentials", file=sys.stderr)
|
|
80
82
|
sys.exit(1)
|
|
81
83
|
|
|
82
|
-
result = hosting_credentials(chat_id, platform, credentials
|
|
84
|
+
result = hosting_credentials(chat_id, platform, credentials)
|
|
83
85
|
print(json.dumps(result, ensure_ascii=False, indent=2))
|
|
84
86
|
|
|
85
87
|
|