关于去重

DefectDojo 旨在批量导入来自各类工具的报告,并根据报告内容创建一个或多个发现项。在使用 DefectDojo 时,您很可能会定期导入来自同一工具的报告,这意味着重复发现项的出现是很常见的。

这正是去重功能发挥作用的地方,这是一项智能功能,您可以通过设置来自动管理重复的发现项。

DefectDojo 如何处理重复项

  1. 首先,您导入测试 1。您的报告中包含一个漏洞,该漏洞被记录为发现项 A。
  2. 随后,您导入测试 2,其中包含相同的漏洞。该漏洞将被记录为发现项 B,且发现项 B 会被标记为发现项 A 的重复项。
  3. 之后,您又导入了测试 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_pathline 均为空,通常不会发生去重。

后台处理

  • 去重会在导入/重新导入时触发,也会在通过 Celery 在后台运行的某些更新过程中触发。

导入/重新导入去重执行模式

对于导入和重新导入,您可以控制去重后处理的调度方式,以及 API 响应是否需要等待其完成。您可以在个人资料页面按用户设置(去重执行模式),也可以通过导入/重新导入端点上的 deduplication_execution_mode 字段按请求覆盖该设置(请求中的值优先于个人资料中的设置)。

  • async(默认):去重及其余后处理均在后台运行,响应会立即返回。这是历史遗留行为;响应会在发现项完成去重之前就已生成。
  • async_wait:后处理仍会调度到后台执行,但请求会等待去重完成后才响应。此时 scan_added 通知以及响应中的统计信息会反映去重后的状态(最终被判定为重复项的发现项将不再被计入或列为新发现项)。JIRA 推送、产品评级等非去重任务仍保持异步,不会被等待。等待时间上限由 DD_DEDUPLICATION_ASYNC_WAIT_TIMEOUT(默认 60 秒)控制;如果在此时间内没有工作进程接手该任务,请求仍会照常响应,而不会一直挂起。
  • sync:导入去重会在 Web 请求中内联执行。

导入/重新导入的响应中包含一个布尔字段 deduplication_complete,用于指示在响应生成时去重是否已经完成(sync 以及成功完成的 async_waittrueasyncfalse)。

这与全局的 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. 首先,您导入测试 1。您的报告中包含一个漏洞,该漏洞被记录为发现项 A。
  2. 随后,您导入的测试 2 包含相同的漏洞。该漏洞将被记录为发现项 B,且发现项 B 会被标记为发现项 A 的重复项。
  3. 之后,您又导入了测试 3,其中同样包含该漏洞。该漏洞将被记录为发现项 C,并被标记为发现项 A 的重复项。此时,由于已超过最大重复数的阈值,发现项 B 将从 DefectDojo 中被删除。

应用此设置

应用删除重复发现项设置后会立即开始删除流程。该设置可在系统设置页面中应用。更多信息请参见“启用去重”。

去重故障排查

有时去重功能可能无法按预期工作。以下是一些去重功能可能出现异常的示例,以及相应的可能解决方案。

您看到的现象最可能的原因需要调整的内容
仅行号发生变化时,重新导入却关闭了旧发现项并创建了新发现项重新导入匹配使用了不稳定的字段(例如行号)重新导入去重(优先使用稳定的 ID 或稳定的哈希字段)
同一测试中创建了多个您认为应属于重复项的发现项未针对该工具或范围配置去重匹配同工具去重(并可考虑“删除重复发现项”行为)
不同工具之间产生了重复项跨工具匹配已禁用或过于严格跨工具去重(仅限 Pro 版)(基于哈希的匹配)
同一 SCA 依赖项被导入多个产品后,产生的是各自独立的发现项,而非重复项默认情况下去重范围限定在单个产品内全局组件去重(仅限 Pro 版)为您的 SCA 工具启用),或者,在位置数据模型下使用全局位置去重(仅限 Pro 版)按共享位置匹配
同一 URL / Web 发现项被导入多个产品后,产生的是各自独立的发现项,而非重复项默认情况下去重范围限定在单个产品内,且全局组件去重只匹配组件全局位置去重(仅限 Pro 版)跨产品匹配 DAST/URL 发现项
跨多个测试反复创建同一发现项的过量重复项资产层级设置不正确考虑针对持续测试使用重新导入

当自动去重未能识别出您认为本应关联的发现项时,您可以在“查看发现项”页面中手动将它们关联起来。有关如何发现相关发现项并手动将其标记为重复项,请参见“相似发现项”(开源版 | Pro 版)。