关于去重
DefectDojo 旨在批量导入来自各类工具的报告,并根据报告内容创建一个或多个发现项。在使用 DefectDojo 时,您很可能会定期导入来自同一工具的报告,这意味着重复发现项的出现是很常见的。
这正是去重功能发挥作用的地方,这是一项智能功能,您可以通过设置来自动管理重复的发现项。
DefectDojo 如何处理重复项
- 首先,您导入测试 1。您的报告中包含一个漏洞,该漏洞被记录为发现项 A。
- 随后,您导入测试 2,其中包含相同的漏洞。该漏洞将被记录为发现项 B,且发现项 B 会被标记为发现项 A 的重复项。
- 之后,您又导入了测试 3,其中同样包含该漏洞。该漏洞将被记录为发现项 C,并被标记为发现项 A 的重复项。
通过以这种方式创建并标记重复项,DefectDojo 确保针对“原始”漏洞的所有处理工作都集中在原始发现项页面上,既不会产生独立的上下文,也不会让团队误以为存在多个需要分别处理的漏洞。
哪个发现项会成为原始项
去重功能始终将重复链中最早创建的发现项视为规范的原始项,因此来自较早导入的发现项永远不会被降级为较新发现项的重复项——已经确立的原始项不会易主。
在同一份报告内部,扫描工具列出发现项的顺序并不能决定谁是“胜出者”。同一次导入中的发现项会按照稳定的、基于内容推导出的顺序创建,因此如果某份报告中有多个发现项在同一个去重键上发生冲突,每次导入该报告都会得到相同的原始项。重复扫描并重新导入相同的结果,不会打乱您的团队一直在处理的发现项。
默认情况下,这些测试需要嵌套在同一个产品下,去重功能才会生效。如果需要,您还可以将去重范围进一步限定在单个测试活动内。

重复的发现项默认会被设置为非活动状态。这并不是说重复发现项本身处于非活动状态,而是为了让您的团队只需处理和修复一个活动发现项,其含义是:一旦原始发现项被标记为已缓解,其重复项也会随之被标记为已缓解。
重新导入去重
去重与重新导入是两个相似的流程,但它们使用不同的算法来识别发现项匹配。
- 当您对某个测试执行重新导入时,重新导入流程会检查传入的发现项,比较哈希码,并丢弃任何匹配项。这些匹配项永远不会被创建为发现项或重复发现项。
但是,任何在重新导入去重之后仍然保留下来的发现项,依然会受到同工具去重的影响。因此,如果您为同工具去重设置了更窄的范围,仍可能在重新导入流程中出现重复项。
示例
下面是一个重新导入去重算法与同工具去重算法不同的工具示例。
| 去重算法 | 哈希码字段 |
|---|---|
| 重新导入 | 标题、CWE、严重程度、描述、行号 |
| 同工具 | 标题、CWE、严重程度、描述 |
假设 DefectDojo 中有一个发现项,具有特定的行号。您重新扫描了您的环境,该漏洞的行号发生了变化。您将结果重新导入到同一个测试中。以下是重新导入和去重过程中会发生的情况:
- 在重新导入过程中,由于行号不同,该发现项不会与任何已有的发现项匹配,因此测试中会创建一个新的发现项。
- 重新导入完成后,同工具去重算法会运行。在此配置下,同工具去重不考虑行号,因此新发现项将被标记为重复项。
重新导入可能会在发现项被记录之前将其完全丢弃,因此调整重新导入去重设置时应格外谨慎。
什么时候适合保留重复项?
当您处理的是共享但彼此独立的测试上下文时,重复项会很有用。例如,如果您的产品上传了两个不同代码仓库的测试结果,且需要对它们进行比较,那么了解哪些漏洞在这些代码仓库之间是共有的会很有帮助。
但是,如果 DefectDojo 产生了过多的重复项,这也可能表明您需要调整流水线或导入流程。
我的重复项说明了什么?
- 同一个漏洞,但在不同的上下文中被发现: 这是使用重复发现项的恰当方式。如果有许多组件受到同一漏洞的影响,您很可能希望了解哪些组件受到了影响,以便掌握问题的范围。
- 同一个漏洞,在相同的上下文中被发现:对于这种情况,存在更好的选择。如果重复发现项没有为您提供关于该漏洞的任何新上下文,或者您发现自己经常需要忽略或删除重复的发现项,这就表明您的流程可以改进。例如,重新导入功能可以让您有效地管理来自 CI/CD 流水线的传入报告。重新导入不会为每个重复项创建全新的发现项对象,而是会记录传入的重复项,但完全不会创建重复发现项。
概述
DefectDojo 开源版支持四种去重算法,可按解析器(测试类型)分别选择:
- 来自工具的唯一 ID:使用扫描工具提供的唯一标识符。
- 哈希码:使用一组已配置的字段来计算哈希值。
- 来自工具的唯一 ID 或哈希码:优先使用工具的唯一 ID;当找不到匹配的唯一 ID 时,回退使用哈希值。
- 旧版算法:具有多个判定条件的历史算法,仅在开源版本中可用。
DefectDojo Pro 版提供了更多选择。 另外两种算法会在实例中的所有产品范围内进行匹配,而不仅限于单个产品或测试活动内——全局组件(按组件名称和版本匹配)和全局漏洞 ID(按 CVE、GHSA 等匹配)。这两种算法默认关闭,需由 DefectDojo 支持团队启用。Pro 版还允许哈希码算法将发现项的漏洞 ID 和 CWE 视为集合,可按完全相同的集合匹配、按任意共有值匹配(_partial),或按一方是另一方的子集匹配(_subset)。完整列表、集合匹配字段及其适用规则,请参见去重调优(Pro)。
去重功能的替代方案:误报历史记录
对于刻意不启用去重的实例,可以改用误报历史记录:当同一产品中已有匹配的发现项被判定为误报时,该功能会自动将新传入的发现项也标记为误报。该功能与去重功能互斥——DefectDojo 不允许同时启用两者——并且目前仍标记为实验性功能。
各算法如何评估端点
根据所用算法和配置的不同,端点对去重的影响方式也有所不同。
来自工具的唯一 ID
- 去重使用
unique_id_from_tool(或vuln_id_from_tool)。 - 在重复项匹配中会忽略端点。
- 发现项的哈希值可能仍会为其他功能而计算,但在此算法下不会影响去重结果。
哈希码
- 去重使用根据
HASHCODE_FIELDS_PER_SCANNER中为给定解析器指定的字段所计算出的哈希值。 - 该哈希值还包含来自
HASH_CODE_FIELDS_ALWAYS的字段(参见下文的“服务字段”部分)。 - 端点可以通过两种方式影响去重:
- 如果扫描工具的哈希字段中包含
endpoints,则端点是哈希值的一部分,必须相应匹配。
- 如果扫描工具的哈希字段中包含
- 如果扫描工具的哈希字段不包含
endpoints,可以通过DEDUPE_ALGO_ENDPOINT_FIELDS(开源版设置)启用可选的基于端点的匹配。配置方式如下:- 将其设置为空列表
[],即可完全忽略端点。 - 将其设置为一个端点属性列表(例如
["host", "port"])。只要两个发现项之间至少有一对端点在所有列出的属性上都匹配,就可以进行去重。
- 将其设置为空列表
来自工具的唯一 ID 或哈希码
如果两个发现项具有相同的 unique_id_from_tool,或者具有相同的 hash_code,则视为互为重复项。
要使发现项被视为重复项,端点也必须匹配,具体规则参见上文的哈希码算法。
旧版算法(仅限开源版)
- 去重会考虑包括端点在内的多个属性。
- 静态发现项与动态发现项的行为有所不同:
- 静态发现项: 新发现项必须包含原始发现项的所有端点。新发现项拥有额外的端点是被允许的。
- 动态发现项: 端点必须严格匹配(通常按主机和端口匹配);端点不同则无法去重。
- 如果没有端点,且
file_path和line均为空,通常不会发生去重。
后台处理
- 去重会在导入/重新导入时触发,也会在通过 Celery 在后台运行的某些更新过程中触发。
导入/重新导入去重执行模式
对于导入和重新导入,您可以控制去重后处理的调度方式,以及 API 响应是否需要等待其完成。您可以在个人资料页面按用户设置(去重执行模式),也可以通过导入/重新导入端点上的 deduplication_execution_mode 字段按请求覆盖该设置(请求中的值优先于个人资料中的设置)。
async(默认):去重及其余后处理均在后台运行,响应会立即返回。这是历史遗留行为;响应会在发现项完成去重之前就已生成。async_wait:后处理仍会调度到后台执行,但请求会等待去重完成后才响应。此时scan_added通知以及响应中的统计信息会反映去重后的状态(最终被判定为重复项的发现项将不再被计入或列为新发现项)。JIRA 推送、产品评级等非去重任务仍保持异步,不会被等待。等待时间上限由DD_DEDUPLICATION_ASYNC_WAIT_TIMEOUT(默认60秒)控制;如果在此时间内没有工作进程接手该任务,请求仍会照常响应,而不会一直挂起。sync:导入去重会在 Web 请求中内联执行。
导入/重新导入的响应中包含一个布尔字段 deduplication_complete,用于指示在响应生成时去重是否已经完成(sync 以及成功完成的 async_wait 为 true,async 为 false)。
这与全局的 block_execution 个人资料标志是相互独立的,后者会强制将用户的所有异步任务(通知、JIRA 推送、产品评级、去重等)转为前台执行。如果未设置执行模式,block_execution=True 时会回退为 sync。
服务字段及其影响
- 默认情况下,
HASH_CODE_FIELDS_ALWAYS = ["service"],这意味着对所有扫描工具而言,发现项关联的service都会被附加到哈希值中。 - 实际影响:
- 两个原本完全相同、但
service值不同的发现项会产生不同的哈希值,在基于哈希的路径下不会被去重。 - 在导入/重新导入过程中,界面中填写的
Service字段可以覆盖解析器提供的服务值。更改该值可能会改变哈希值,从而影响去重结果。 - 如果您希望服务字段不影响去重,请相应地配置
HASH_CODE_FIELDS_ALWAYS(参见开源版调优页面)。将service从始终包含的列表中移除后,它就不会再影响哈希值。
- 两个原本完全相同、但
删除重复发现项
如果您有大量希望删除的重复发现项,可以在系统设置中启用删除重复发现项选项。
删除重复发现项与最大重复数字段结合使用,可以让 DefectDojo 限制存储的重复发现项数量。启用此字段后,DefectDojo 只会保留一定数量的重复发现项。
哪些重复项会被删除?
原始发现项永远不会被 DefectDojo 自动删除,但一旦超过最大重复数的阈值,DefectDojo 就会自动删除最旧的重复发现项。
举例来说,假设您将最大重复数字段设置为“1”。
- 首先,您导入测试 1。您的报告中包含一个漏洞,该漏洞被记录为发现项 A。
- 随后,您导入的测试 2 包含相同的漏洞。该漏洞将被记录为发现项 B,且发现项 B 会被标记为发现项 A 的重复项。
- 之后,您又导入了测试 3,其中同样包含该漏洞。该漏洞将被记录为发现项 C,并被标记为发现项 A 的重复项。此时,由于已超过最大重复数的阈值,发现项 B 将从 DefectDojo 中被删除。
应用此设置
应用删除重复发现项设置后会立即开始删除流程。该设置可在系统设置页面中应用。更多信息请参见“启用去重”。
去重故障排查
有时去重功能可能无法按预期工作。以下是一些去重功能可能出现异常的示例,以及相应的可能解决方案。
| 您看到的现象 | 最可能的原因 | 需要调整的内容 |
|---|---|---|
| 仅行号发生变化时,重新导入却关闭了旧发现项并创建了新发现项 | 重新导入匹配使用了不稳定的字段(例如行号) | 重新导入去重(优先使用稳定的 ID 或稳定的哈希字段) |
| 同一测试中创建了多个您认为应属于重复项的发现项 | 未针对该工具或范围配置去重匹配 | 同工具去重(并可考虑“删除重复发现项”行为) |
| 不同工具之间产生了重复项 | 跨工具匹配已禁用或过于严格 | 跨工具去重(仅限 Pro 版)(基于哈希的匹配) |
| 同一 SCA 依赖项被导入多个产品后,产生的是各自独立的发现项,而非重复项 | 默认情况下去重范围限定在单个产品内 | 全局组件去重(仅限 Pro 版)(为您的 SCA 工具启用),或者,在位置数据模型下使用全局位置去重(仅限 Pro 版)(按共享位置匹配) |
| 同一 URL / Web 发现项被导入多个产品后,产生的是各自独立的发现项,而非重复项 | 默认情况下去重范围限定在单个产品内,且全局组件去重只匹配组件 | 全局位置去重(仅限 Pro 版)(跨产品匹配 DAST/URL 发现项) |
| 跨多个测试反复创建同一发现项的过量重复项 | 资产层级设置不正确 | 考虑针对持续测试使用重新导入 |
当自动去重未能识别出您认为本应关联的发现项时,您可以在“查看发现项”页面中手动将它们关联起来。有关如何发现相关发现项并手动将其标记为重复项,请参见“相似发现项”(开源版 | Pro 版)。