| name | performing-web-application-vulnerability-triage |
| description | 使用 OWASP 风险评级方法论对 DAST/SAST 扫描器的 Web 应用程序漏洞发现进行分类,区分真阳性和假阳性,并确定修复优先级。 |
| domain | cybersecurity |
| subdomain | vulnerability-management |
| tags | ["web-application","vulnerability-triage","owasp","dast","sast","burp-suite","zap","false-positive","risk-rating"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
执行 Web 应用程序漏洞分类
概述
Web 应用程序漏洞分类(Triage)是审查 DAST(动态应用安全测试)和 SAST(静态应用安全测试)工具发现的过程,用于验证真阳性、排除假阳性、使用 OWASP 风险评级方法论分配风险等级,并确定修复优先级。有效的分类减少告警疲劳,使开发团队专注于最重要的漏洞。
前置条件
- DAST 扫描结果(OWASP ZAP、Burp Suite、Acunetix)
- SAST 扫描结果(Semgrep、SonarQube、Checkmarx、Snyk Code)
- Python 3.9+,安装
requests、beautifulsoup4
- Burp Suite Professional 或 OWASP ZAP 用于手动验证
- DefectDojo 或类似工具用于发现管理
OWASP 风险评级方法论
风险计算
风险 = 可能性 × 影响
可能性因素(0-9 分)
| 因素组 | 因素 | 描述 |
|---|
| 威胁主体 | 技能水平 | 攻击者的技术熟练程度? |
| 威胁主体 | 动机 | 攻击者的积极性? |
| 威胁主体 | 机会 | 需要什么资源/访问权限? |
| 威胁主体 | 规模 | 潜在威胁主体群体有多大? |
| 漏洞 | 发现难度 | 找到漏洞有多容易? |
| 漏洞 | 利用难度 | 利用漏洞有多容易? |
| 漏洞 | 知名度 | 漏洞的知名程度? |
| 漏洞 | 入侵检测 | 利用被检测的可能性? |
影响因素(0-9 分)
| 因素组 | 因素 | 描述 |
|---|
| 技术 | 机密性 | 可能泄露多少数据? |
| 技术 | 完整性 | 可能篡改多少数据? |
| 技术 | 可用性 | 可能损失多少服务? |
| 技术 | 可追责性 | 行为能否追溯到攻击者? |
| 业务 | 财务损失 | 收入损失、监管罚款 |
| 业务 | 声誉损失 | 品牌信任侵蚀 |
| 业务 | 合规违规 | 监管违规风险 |
| 业务 | 隐私侵犯 | PII/PHI 暴露量 |
风险矩阵
| 低影响(0-3) | 中影响(3-6) | 高影响(6-9) |
|---|
| 高可能性(6-9) | 中 | 高 | 严重 |
| 中可能性(3-6) | 低 | 中 | 高 |
| 低可能性(0-3) | 注意 | 低 | 中 |
分类流程
步骤 1:按 OWASP Top 10 分类
OWASP_TOP_10_2021 = {
"A01": "访问控制失效",
"A02": "加密失败",
"A03": "注入",
"A04": "不安全设计",
"A05": "安全配置错误",
"A06": "脆弱和过时组件",
"A07": "身份识别和认证失败",
"A08": "软件和数据完整性失败",
"A09": "安全日志记录和监控失败",
"A10": "服务器端请求伪造(SSRF)",
}
CWE_TO_OWASP = {
"CWE-79": "A03",
"CWE-89": "A03",
"CWE-78": "A03",
"CWE-352": "A01",
"CWE-22": "A01",
"CWE-200": "A02",
"CWE-327": "A02",
"CWE-287": "A07",
"CWE-918": "A10",
"CWE-502": "A08",
"CWE-611": "A05",
}
步骤 2:验证真阳性与假阳性
def triage_finding(finding):
"""将发现分类为 true_positive、false_positive 或 needs_review。"""
fp_indicators = [
"Content-Security-Policy header not set",
"X-Content-Type-Options header missing",
"Cookie without SameSite attribute",
]
for indicator in fp_indicators:
if indicator.lower() in finding.get("title", "").lower():
if finding.get("severity", "").lower() in ("info", "low"):
return "false_positive", "常见信息性发现"
if finding.get("evidence") and finding.get("confidence", "").lower() == "certain":
return "true_positive", "扫描器已确认利用"
if finding.get("source") == "sast":
if finding.get("cwe") in ["CWE-89", "CWE-78", "CWE-79"]:
return "needs_review", "注入发现需要手动代码审查"
return ,
步骤 3:风险评分计算
def calculate_risk_score(finding, app_context):
"""计算 Web 应用程序发现的 OWASP 风险等级。"""
likelihood = {
"skill_level": 6 if finding["cwe"] in ["CWE-89", "CWE-79"] else 4,
"motive": 7,
"opportunity": 7 if finding.get("authenticated") == False else 4,
"size": 9 if finding.get("internet_facing") else 4,
"ease_of_discovery": 8 if finding.get("scanner_detected") else 5,
"ease_of_exploit": 7 if finding.get("exploit_available") else 4,
"awareness": 6,
"intrusion_detection": 3 if app_context.get("waf_enabled") else 8,
}
impact = {
"confidentiality": 9 finding.get(, []) ,
: finding[] [, ] ,
: finding.get(, []) ,
: app_context.get() ,
: app_context.get() ,
: app_context.get() ,
: app_context.get() ,
: app_context.get() ,
}
likelihood_score = (likelihood.values()) / (likelihood)
impact_score = (impact.values()) / (impact)
risk_score = likelihood_score * impact_score
risk_score >= :
risk_level =
risk_score >= :
risk_level =
risk_score >= :
risk_level =
risk_score >= :
risk_level =
:
risk_level =
{
: (likelihood_score, ),
: (impact_score, ),
: (risk_score, ),
: risk_level,
}
步骤 4:生成分类报告
python3 scripts/process.py \
--input zap_results.json \
--format zap \
--app-context app_config.json \
--output triage_report.json
手动验证技术
SQL 注入验证
# 使用单引号测试参数
GET /search?q=test' HTTP/1.1
# 使用基于布尔的载荷测试
GET /search?q=test' AND 1=1-- HTTP/1.1
GET /search?q=test' AND 1=2-- HTTP/1.1
# 基于时间的验证
GET /search?q=test'; WAITFOR DELAY '0:0:5'-- HTTP/1.1
XSS 验证
# 反射型 XSS 测试
GET /search?q=<script>alert(document.domain)</script> HTTP/1.1
# 检查输出是否已编码
GET /search?q="><img src=x onerror=alert(1)> HTTP/1.1
# DOM 型 XSS
GET /page#<img src=x onerror=alert(1)> HTTP/1.1
参考资料