TheAuditorTool/BenchProctor

GitHub: TheAuditorTool/BenchProctor

一个开放的 SAST 基准语料库,通过组合生成的漏洞与安全代码样本,对任意输出 SARIF 2.1.0 的静态分析工具进行准确度评分。

Stars: 7 | Forks: 2

# BenchProctor **SAST 的真实基准。** 一个开放、机器可验证的基准测试语料库,用于衡量静态分析工具发现真实漏洞的准确度——以及它对安全代码误报的频率。 **[benchproctor.com](https://benchproctor.com)** · [博客](https://blog.benchproctor.com) · Apache-2.0 SAST 工具的可信度取决于其准确度,而如果没有真实基准(ground truth),准确度就无法衡量。BenchProctor 为您提供带有标记的语料库——标记为 `vulnerable`(存在漏洞)或 `safe`(安全)的程序——这样您就可以对任何输出 SARIF 2.1.0 的工具进行评分,并获得真实的指标:真阳性率(true-positive rate)、假阳性率(false-positive rate)以及整体检测准确度(Youden's J)。 ## 快速开始 ``` # 1. 运行你的 scanner 对抗一个 suite,导出 SARIF 2.1.0 your-tool scan ./Benchmarks/normal/java/spring --format sarif -o results.sarif # 2. 对照 answer key 进行评分(standard-library Python,zero dependencies) python scripts/score_sarif.py results.sarif Benchmarks/normal/java/spring/expectedresults-*.csv # 3. 读取 TPR、FPR 和你的 Youden's J — 包含按类别平均和 flat aggregate ``` 评分器会从 SARIF 的 `ruleId`、结果/规则的 `properties` 或 `tags`(例如 `external/cwe/cwe-089`)或 CWE `taxa` 中恢复每个发现的 CWE——因此大多数工具无需额外配置即可使用。如果您的工具完全没有输出 CWE,请添加 `--match-mode filename`(在存在漏洞的文件上的任何发现都会计分;由于这会纵容过度标记,因此建议优先使用默认设置)。 ## 为什么需要另一个基准测试 现有的公开 SAST 基准测试都有三个结构性缺陷: - **手动编写且一成不变。** 固定的一组人工编写用例发布后便不再更新,因此各种工具——以及背后的模型——会对它产生过拟合(overfit)。高分不再代表真实世界的准确度。 - **文件名泄露了答案。** 当测试位于 `sqli/Test01729_true_positive.java` 时,扫描器可以通过匹配路径来获得高分,而不是通过分析代码。 - **单一语言、单一文件、毫无防御。** 真实的发现往往跨越多个文件、服务和语言,并且紧挨着几乎生效的过滤器(sanitizer)。单文件、单语言的测试套件永远无法检验这些情况。 BenchProctor 的构建旨在消除这三个缺陷。 ## 语料库包含什么 | | | |---|---| | **当前可用** | Java (Spring, Jakarta EE) · Python (Flask, Django, FastAPI) — 独立运行 | | **漏洞类型** | Java + Python 共支持约 210 个映射到 CWE 的类别 | | **每种语言的规模** | `quicktest` · `normal` · `enterprise`(见下文) | | **样本平衡** | 每个类别中,存在漏洞 / 安全的比例为 50 / 50 | | **路线图** | Go, Rust, TypeScript, JavaScript, PHP, Ruby, Bash — 见 [roadmap.md](roadmap.md) | 每种语言都提供三种规模,因此您可以在运行时间和测试深度之间进行权衡: - **`quicktest`**(每种语言约 1 万个测试)— 包含最常见的 CWE,每种类型包含 25 个存在漏洞 + 25 个安全的样本。适合快速初步评估。 - **`normal`**(约 4 万个)— 包含几乎所有受支持的 CWE,每种类型包含 50 + 50 个样本。核心的可评分语料库。 - **`enterprise`**(包含所有 CWE,最深度的采样,每种类型多达 200 + 200 个样本)— 用于获得严密的置信区间。 - **组合生成,而非人工编写。** 每个类别都是一个漏洞类别,表现为跨越四个维度的污点流(taint flow):不可信输入进入的位置(**source**)、它如何传播(**propagator**)、什么会中和它(**sanitizer**),以及它到达的危险调用(**sink**)。语料库是通过组合这些构建块(42 个 source × 40 个 propagator × 65 个 sanitizer × 58 个 sink)生成的:存在漏洞的用例缺少有效的 sanitizer;而其安全孪生体则应用了 sanitizer。每个生成的组合都被限制为符合真实的逻辑流。 - **结构上防止泄露。** 生成的文件不包含注释、CWE 标签、类别名称,标识符中也没有任何提示。文件 ID 是随机打乱的,因此文件名不会透露有关文件类别或标记的任何信息。CSV 答案键是唯一的真实基准。 - **季度轮换。** 每个版本都是通过固定种子生成的,该种子会改变*生成哪些*组合——因此实际代码在每个季度都会有所不同——同时保持所有与评分相关的不变量(CWE 标识、难度分布、50/50 平衡、语言/框架覆盖范围)恒定。相同的种子可以逐字节重现语料库;新的种子会生成您无法针对其进行预训练的新变体。上一个季度的分数仍然具有可比性。 ## 难度所在 检测出赤裸裸的 `eval(input)` 只是基本操作。每个类别的权重都倾向于那些能区分真正的分析器和简单的模式匹配器的用例: - **逼真的框架代码。** 真实的请求访问器、DTO / Pydantic 模型、ORM 和驱动程序调用——污点流贯穿的是符合语言习惯的代码,而非玩具般的代码片段。 - **失效的 sanitizer 变体。** 存在 sanitizer 但被绕过——有缺陷的正则表达式、上下文错误的转义、不足的长度限制。信任 sanitizer 存在性的扫描器会将这些错误地标记为存在漏洞的安全孪生体;而真正有效的孪生体则是真正安全的。 - **多步污点。** Source 到 sink 之间通过 propagator 连接——解码、集合往返、条件分发——这是与路径无关的匹配器会丢失的信息。 跨文件的 CWE 链、多语言微服务场景以及对抗性 / SAST 规避用例已列入[路线图](roadmap.md);此版本仅限于单文件独立运行。 ## 语言与框架 **当前可用(独立运行):** | 语言 | 框架 | |---|---| | Java | Spring, Jakarta EE | | Python | Flask, Django, FastAPI | **路线图中**(每种语言在通过相同的测试关卡后即发布):Go (net/http, Gin) · Rust (Actix-web, Axum) · TypeScript (NestJS, Express) · JavaScript (Express, Koa) · PHP (Laravel, Symfony) · Ruby (Rails, Sinatra) · Bash。添加一种语言不会改变任何类别,因此覆盖率在整个矩阵中保持一致。 ## Web 风险类别覆盖范围 | 类别 | 已覆盖 / 已映射 | | |---|---|---| | A01 失效的访问控制 | 37 / 40 | 92% | | A02 安全配置错误 | 11 / 16 | 69% | | A03 软件供应链 | 0 / 6 | 属于组合分析,而非代码模式的 SAST | | A04 加密失败 | 30 / 32 | 94% | | A05 注入 | 31 / 37 | 83% | | A06 不安全的设计 | 27 / 39 | 69% | | A07 身份验证失败 | 34 / 36 | 94% | | A08 软件和数据完整性失败 | 8 / 14 | 57% | | A09 日志记录和监控失败 | 5 / 5 | 100% | | A10 异常条件处理失败 | 22 / 24 | 92% | 已映射 249 个 CWE 中的 213 个(85.5%)。其余部分属于配置级、供应链或仅限运行时的范畴——无法表示为静态代码模式。 ## 评分 每个测试用例都在 CSV 答案键中带有真实基准标记(`vulnerable` 或 `safe`)。工具运行后,评分系统会计算出一个混淆矩阵(confusion matrix)和一个减法结果: ``` detected ignored vulnerable TP FN safe FP TN TPR = TP / (TP + FN) detection rate FPR = FP / (FP + TN) false-alarm rate J = TPR - FPR Youden's J (the score) ``` | 分数 | 含义 | |------:|---------| | +100% | 完美——抓住所有漏洞,零误报 | | 0% | 仅与盲目猜测无异(即在 50/50 语料库上,标记一切的工具所处的水平) | | -100% | 颠倒——标记安全代码,漏掉真实 bug | 分数通过两种方式报告:**类别平均**(每个类别的权重相等,因此大类无法占据主导——这是核心指标)和 **总体汇总**。任何输出 SARIF 2.1.0 的工具都可以进行评分;评分器是一个仅使用标准库且无依赖的单一 Python 文件。 ## 标记是如何验证的 在发布某种语言之前,每个生成的文件都必须通过一套关卡测试套件:它必须能够编译(或解析),每个 `vulnerable` 用例都必须包含真实的从 source 到 sink 的污点流,每个 `safe` 孪生体必须确实为该 sink 中和了污点,并且记录的 sink 行必须是漏洞实际所在的行。 这里发布的只是测试代码(testcode)加上 CSV 答案键——仅此而已。我们故意**没有**发布每个文件的证明元数据和用于自我验证的满分预言机(oracle)SARIF,因此无法通过已发布的文件重建答案键。 ## 发布 语料库按季度进行版本控制和发布。`scripts/score_sarif.py` 中的评分器仅使用标准库 Python——只需克隆,将其指向语料库和您的 SARIF,即可读取您的分数。 ## 许可证 Apache License 2.0 — 见 [LICENSE](LICENSE)。由 BenchProctor 的作者创建和维护。
标签:JS文件枚举, 逆向工具