Refine security score calculation logic and enforce mandatory fields for findings in JSON format
Build and Push CodeReview / build (push) Waiting to run
Details
Build and Push CodeReview / build (push) Waiting to run
Details
This commit is contained in:
parent
b373692577
commit
7f951d5451
|
|
@ -1354,37 +1354,96 @@ async def _save_findings(
|
||||||
def _calculate_security_score(findings: List[Dict]) -> float:
|
def _calculate_security_score(findings: List[Dict]) -> float:
|
||||||
"""计算安全评分
|
"""计算安全评分
|
||||||
|
|
||||||
评分逻辑:从 100 分开始,根据漏洞严重程度扣分
|
评分逻辑:从 100 分开始,根据漏洞严重程度和数量扣分。
|
||||||
- Critical: -25分
|
|
||||||
- High: -15分
|
|
||||||
- Medium: -8分
|
|
||||||
- Low: -3分
|
|
||||||
- Info: -1分
|
|
||||||
|
|
||||||
🔥 FIX: 确保 severity 转换为小写后再匹配 deductions 字典
|
使用递减扣分机制:同类漏洞越多,每个额外漏洞的扣分越少。
|
||||||
|
这样可以避免发现多个漏洞就直接得0分的问题。
|
||||||
|
|
||||||
|
扣分规则(第N个同类漏洞的扣分):
|
||||||
|
- Critical: 第1个-20, 第2个-15, 第3个-10, 第4个及以后-5
|
||||||
|
- High: 第1个-12, 第2个-8, 第3个-5, 第4个及以后-3
|
||||||
|
- Medium: 第1个-5, 第2个-3, 第3个及以后-2
|
||||||
|
- Low: 第1个-2, 第2个及以后-1
|
||||||
|
- Info: 每个-0.5
|
||||||
|
|
||||||
|
最高扣分上限为85分,确保最低得分不会低于15分。
|
||||||
"""
|
"""
|
||||||
if not findings:
|
if not findings:
|
||||||
return 100.0
|
return 100.0
|
||||||
|
|
||||||
# 基于发现的严重程度计算扣分
|
# 统计各严重程度的数量
|
||||||
deductions = {
|
severity_counts = {
|
||||||
"critical": 25,
|
"critical": 0,
|
||||||
"high": 15,
|
"high": 0,
|
||||||
"medium": 8,
|
"medium": 0,
|
||||||
"low": 3,
|
"low": 0,
|
||||||
"info": 1,
|
"info": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
total_deduction = 0
|
|
||||||
for f in findings:
|
for f in findings:
|
||||||
if isinstance(f, dict):
|
if isinstance(f, dict):
|
||||||
# 🔥 FIX: 将 severity 转换为小写,确保能正确匹配 deductions 字典
|
|
||||||
raw_sev = f.get("severity") or f.get("risk") or "low"
|
raw_sev = f.get("severity") or f.get("risk") or "low"
|
||||||
sev = str(raw_sev).lower().strip()
|
sev = str(raw_sev).lower().strip()
|
||||||
deduction = deductions.get(sev, 3) # 默认使用 low 的扣分
|
if sev in severity_counts:
|
||||||
total_deduction += deduction
|
severity_counts[sev] += 1
|
||||||
|
else:
|
||||||
|
severity_counts["low"] += 1 # 未知严重程度按 low 处理
|
||||||
|
|
||||||
|
# 计算递减扣分
|
||||||
|
total_deduction = 0.0
|
||||||
|
|
||||||
|
# Critical: 20, 15, 10, 5, 5, ...
|
||||||
|
for i in range(severity_counts["critical"]):
|
||||||
|
if i == 0:
|
||||||
|
total_deduction += 20
|
||||||
|
elif i == 1:
|
||||||
|
total_deduction += 15
|
||||||
|
elif i == 2:
|
||||||
|
total_deduction += 10
|
||||||
|
else:
|
||||||
|
total_deduction += 5
|
||||||
|
|
||||||
|
# High: 12, 8, 5, 3, 3, ...
|
||||||
|
for i in range(severity_counts["high"]):
|
||||||
|
if i == 0:
|
||||||
|
total_deduction += 12
|
||||||
|
elif i == 1:
|
||||||
|
total_deduction += 8
|
||||||
|
elif i == 2:
|
||||||
|
total_deduction += 5
|
||||||
|
else:
|
||||||
|
total_deduction += 3
|
||||||
|
|
||||||
|
# Medium: 5, 3, 2, 2, ...
|
||||||
|
for i in range(severity_counts["medium"]):
|
||||||
|
if i == 0:
|
||||||
|
total_deduction += 5
|
||||||
|
elif i == 1:
|
||||||
|
total_deduction += 3
|
||||||
|
else:
|
||||||
|
total_deduction += 2
|
||||||
|
|
||||||
|
# Low: 2, 1, 1, ...
|
||||||
|
for i in range(severity_counts["low"]):
|
||||||
|
if i == 0:
|
||||||
|
total_deduction += 2
|
||||||
|
else:
|
||||||
|
total_deduction += 1
|
||||||
|
|
||||||
|
# Info: 0.5 each
|
||||||
|
total_deduction += severity_counts["info"] * 0.5
|
||||||
|
|
||||||
|
# 最高扣分上限为85分
|
||||||
|
total_deduction = min(total_deduction, 85.0)
|
||||||
|
|
||||||
score = max(0, 100 - total_deduction)
|
score = max(0, 100 - total_deduction)
|
||||||
|
|
||||||
|
# 添加日志用于调试
|
||||||
|
logger.debug(
|
||||||
|
f"[SecurityScore] Counts: {severity_counts}, "
|
||||||
|
f"Deduction: {total_deduction:.1f}, Score: {score:.1f}"
|
||||||
|
)
|
||||||
|
|
||||||
return float(score)
|
return float(score)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ Final Answer: {
|
||||||
"文件路径:行号 - 风险描述"
|
"文件路径:行号 - 风险描述"
|
||||||
],
|
],
|
||||||
"initial_findings": [
|
"initial_findings": [
|
||||||
{"title": "...", "file_path": "...", "line_start": ..., "description": "..."}
|
{"title": "...", "file_path": "...", "line_start": ..., "description": "...", "vulnerability_type": "hardcoded_secret/sql_injection/...", "severity": "critical/high/medium/low"}
|
||||||
],
|
],
|
||||||
"summary": "项目侦察总结"
|
"summary": "项目侦察总结"
|
||||||
}
|
}
|
||||||
|
|
@ -167,11 +167,35 @@ Final Answer: {
|
||||||
**禁止**输出纯描述性文本如 "File write operations with user-controlled paths",必须指明具体文件。
|
**禁止**输出纯描述性文本如 "File write operations with user-controlled paths",必须指明具体文件。
|
||||||
|
|
||||||
### initial_findings 格式要求
|
### initial_findings 格式要求
|
||||||
|
|
||||||
|
🚨 **必须包含以下字段用于安全评分计算:**
|
||||||
|
|
||||||
每个发现**必须**包含:
|
每个发现**必须**包含:
|
||||||
- `title`: 漏洞标题
|
- `title`: 漏洞标题
|
||||||
- `file_path`: 具体文件路径
|
- `file_path`: 具体文件路径(必填!)
|
||||||
- `line_start`: 行号
|
- `line_start`: 行号
|
||||||
- `description`: 详细描述
|
- `description`: 详细描述
|
||||||
|
- `vulnerability_type`: 漏洞类型(使用下划线格式,如 `sql_injection`, `command_injection`, `ssrf`, `hardcoded_secret`)
|
||||||
|
- `severity`: 严重程度(**必须使用小写**:`critical`, `high`, `medium`, `low`)
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"title": "明文密码存储",
|
||||||
|
"file_path": "config/settings.py",
|
||||||
|
"line_start": 25,
|
||||||
|
"description": "配置文件中硬编码了数据库密码",
|
||||||
|
"vulnerability_type": "hardcoded_secret",
|
||||||
|
"severity": "high"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
❌ 错误格式(导致安全评分无法计算):
|
||||||
|
```json
|
||||||
|
{"severity": "HIGH", ...} // ❌ 应该用小写 "high"
|
||||||
|
{"severity": "Critical", ...} // ❌ 应该用小写 "critical"
|
||||||
|
{"type": "sqli", ...} // ❌ 应该用 "vulnerability_type": "sql_injection"
|
||||||
|
```
|
||||||
|
|
||||||
## 🚨 防止幻觉(关键!)
|
## 🚨 防止幻觉(关键!)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -266,11 +266,21 @@ Action Input: {"file_path": "search.php"}
|
||||||
3. Action Input 必须是完整的 JSON 对象,不能为空或截断
|
3. Action Input 必须是完整的 JSON 对象,不能为空或截断
|
||||||
|
|
||||||
## Final Answer 格式
|
## Final Answer 格式
|
||||||
|
|
||||||
|
🚨 **必须严格遵守以下字段格式,否则系统无法正确计算安全评分!**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"findings": [
|
"findings": [
|
||||||
{
|
{
|
||||||
...原始发现字段...,
|
"id": 1,
|
||||||
|
"vulnerability_type": "sql_injection/xss/command_injection/ssrf/path_traversal/hardcoded_secret/...",
|
||||||
|
"severity": "critical/high/medium/low/info",
|
||||||
|
"title": "漏洞标题",
|
||||||
|
"description": "漏洞详细描述",
|
||||||
|
"file_path": "相对文件路径",
|
||||||
|
"line_start": 行号,
|
||||||
|
"code_snippet": "漏洞代码片段",
|
||||||
"verdict": "confirmed/likely/uncertain/false_positive",
|
"verdict": "confirmed/likely/uncertain/false_positive",
|
||||||
"confidence": 0.0-1.0,
|
"confidence": 0.0-1.0,
|
||||||
"is_verified": true/false,
|
"is_verified": true/false,
|
||||||
|
|
@ -295,6 +305,32 @@ Action Input: {"file_path": "search.php"}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### ⚠️ 必填字段要求
|
||||||
|
|
||||||
|
| 字段 | 要求 | 示例 |
|
||||||
|
|------|------|------|
|
||||||
|
| `vulnerability_type` | **必填**,使用下划线格式 | `sql_injection`, `command_injection`, `ssrf`, `xss`, `hardcoded_secret` |
|
||||||
|
| `severity` | **必填**,必须使用**小写**值 | `critical`, `high`, `medium`, `low`, `info` |
|
||||||
|
| `title` | **必填**,简洁描述漏洞 | `SQL注入漏洞 in search.php` |
|
||||||
|
| `file_path` | **必填**,相对路径 | `src/controllers/user.py` |
|
||||||
|
| `verdict` | **必填** | `confirmed`, `likely`, `uncertain`, `false_positive` |
|
||||||
|
|
||||||
|
### ❌ 常见错误(导致安全评分计算失败)
|
||||||
|
|
||||||
|
```json
|
||||||
|
// 错误:使用大写 severity
|
||||||
|
{"severity": "HIGH", ...} // ❌ 应该用 "high"
|
||||||
|
{"severity": "Critical", ...} // ❌ 应该用 "critical"
|
||||||
|
|
||||||
|
// 错误:使用 type 而不是 vulnerability_type
|
||||||
|
{"type": "sql_injection", ...} // ❌ 应该用 "vulnerability_type"
|
||||||
|
|
||||||
|
// 错误:severity 值拼写错误
|
||||||
|
{"severity": "critial", ...} // ❌ 拼写错误
|
||||||
|
{"severity": "unknown", ...} // ❌ 无效值
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 验证判定标准
|
## 验证判定标准
|
||||||
- **confirmed**: 漏洞确认存在且可利用,有明确证据(如 Harness 成功触发)
|
- **confirmed**: 漏洞确认存在且可利用,有明确证据(如 Harness 成功触发)
|
||||||
- **likely**: 高度可能存在漏洞,代码分析明确但无法动态验证
|
- **likely**: 高度可能存在漏洞,代码分析明确但无法动态验证
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue