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:
|
||||
"""计算安全评分
|
||||
|
||||
评分逻辑:从 100 分开始,根据漏洞严重程度扣分
|
||||
- Critical: -25分
|
||||
- High: -15分
|
||||
- Medium: -8分
|
||||
- Low: -3分
|
||||
- Info: -1分
|
||||
评分逻辑:从 100 分开始,根据漏洞严重程度和数量扣分。
|
||||
|
||||
🔥 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:
|
||||
return 100.0
|
||||
|
||||
# 基于发现的严重程度计算扣分
|
||||
deductions = {
|
||||
"critical": 25,
|
||||
"high": 15,
|
||||
"medium": 8,
|
||||
"low": 3,
|
||||
"info": 1,
|
||||
# 统计各严重程度的数量
|
||||
severity_counts = {
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"low": 0,
|
||||
"info": 0,
|
||||
}
|
||||
|
||||
total_deduction = 0
|
||||
for f in findings:
|
||||
if isinstance(f, dict):
|
||||
# 🔥 FIX: 将 severity 转换为小写,确保能正确匹配 deductions 字典
|
||||
raw_sev = f.get("severity") or f.get("risk") or "low"
|
||||
sev = str(raw_sev).lower().strip()
|
||||
deduction = deductions.get(sev, 3) # 默认使用 low 的扣分
|
||||
total_deduction += deduction
|
||||
if sev in severity_counts:
|
||||
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)
|
||||
|
||||
# 添加日志用于调试
|
||||
logger.debug(
|
||||
f"[SecurityScore] Counts: {severity_counts}, "
|
||||
f"Deduction: {total_deduction:.1f}, Score: {score:.1f}"
|
||||
)
|
||||
|
||||
return float(score)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ Final Answer: {
|
|||
"文件路径:行号 - 风险描述"
|
||||
],
|
||||
"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": "项目侦察总结"
|
||||
}
|
||||
|
|
@ -167,11 +167,35 @@ Final Answer: {
|
|||
**禁止**输出纯描述性文本如 "File write operations with user-controlled paths",必须指明具体文件。
|
||||
|
||||
### initial_findings 格式要求
|
||||
|
||||
🚨 **必须包含以下字段用于安全评分计算:**
|
||||
|
||||
每个发现**必须**包含:
|
||||
- `title`: 漏洞标题
|
||||
- `file_path`: 具体文件路径
|
||||
- `file_path`: 具体文件路径(必填!)
|
||||
- `line_start`: 行号
|
||||
- `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 对象,不能为空或截断
|
||||
|
||||
## Final Answer 格式
|
||||
|
||||
🚨 **必须严格遵守以下字段格式,否则系统无法正确计算安全评分!**
|
||||
|
||||
```json
|
||||
{
|
||||
"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",
|
||||
"confidence": 0.0-1.0,
|
||||
"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 成功触发)
|
||||
- **likely**: 高度可能存在漏洞,代码分析明确但无法动态验证
|
||||
|
|
|
|||
Loading…
Reference in New Issue