设想一个假设情境。一家销售开票平台的 B2B SaaS 公司正在准备接受一位大型潜在客户的安全审查。几个月前的一次渗透测试产出了一份包含若干发现的报告,其中有一个授权缺陷:一个租户可以通过 API 读取另一个租户的发票。现在,工单系统中所有工单都显示为“已完成”。客户的安全团队提出一个简单的问题:你们如何确认这个缺陷已经消失?在哪些系统上?从哪个构建开始?又是谁决定关闭的?研发负责人找到了一个已合并的拉取请求,却找不到任何复测记录。同一个端点还由一个独立的移动端后端提供服务,而它从未被检查过;另有一个发现被一名开发人员悄悄“接受”了,而且没有设定有效期。这并不是任何真实客户的故事;它只是说明工单状态与实际安全状况会多么迅速地脱节。
本文说明如何把关闭作为一项有证据支撑的决定来管理:每个已确认的发现都有状态、修复责任人、事先定义的验收证据以及明确的有效期或复核触发条件;关闭需要证明在既定条件下行为已经改变,而不是仅凭补丁已合并或工单处于正确的列。
什么是修复管控,关闭从哪里开始
漏洞修复管控是一项确保每个已确认安全发现都被分配责任人、得到修复、经过验证并凭证据关闭的工作规范,而不是仅仅写进报告后便被遗忘。发现问题只是工作的一半。NIST SP 800-115 将技术安全测试的目的描述为规划和实施测试、分析发现并制定缓解策略,这意味着修复跟进与漏洞发现同等重要。
实际问题正是客户提出的问题:漏洞是否真正消失,先修复什么,如何让证据可重复并衡量进展,以及应向复测服务商提出哪些要求。范围涵盖 Web 应用和 API、内部修复流程,以及外部采购的评估与复测工作。本文不能替代法律或合同授权:任何测试或复测,均以系统所有者的明确书面许可和清晰界定的范围为前提。
不应混为一谈的六种状态
关于修复的大多数争议,源于把不同的事情压缩进同一个状态字段。“已解决”可能意味着代码已编写、变更已部署、风险已接受或行为已确认改变:这些是责任人不同的不同事实。
左右滑动查看对照
| 状态 | 记录的内容 | 不能证明的内容 | 通常由谁决定 |
|---|---|---|---|
| 状态 | 在流程中的位置:未关闭、处理中、已缓解、风险已接受、已关闭或已重新打开 | 运行中的系统确实发生了任何变化 | 修复责任人负责保持更新 |
| 修复已实施 | 代码、配置或架构变更已部署到指定环境 | 每个受影响实例上的漏洞行为都已消失 | 实施团队 |
| 验收 | 约定的证据标准已满足,或已批准有文档记录的例外 | 超出约定标准和范围的任何内容 | 结果责任人,依据事先设定的标准 |
| 复测 | 经授权的检查在既定条件下重复了原始测试用例 | 风险永久消失,或不存在其他漏洞 | 验证人,内部或独立均可 |
| 关闭 | 决定不再需要修复工作,并以复测或已批准的例外为依据 | 问题不会在后续版本中再次出现 | 结果责任人,高影响发现还需批准人 |
| 重新打开 | 有证据表明行为再次出现或修复不完整,并关联原始记录 | 原先的关闭不诚实 | 任何掌握证据的人;由责任人确认 |
每个发现都需要一条可核查的记录
管控始于记录,而非工具。每个已确认的发现都应包含:关联原始报告的稳定编号、当前状态、与底层弱点的映射(例如某个 CWE 条目)、受影响实例清单、带版本的验收标准、修复责任人、已收集的证据,以及必须重新复核的条件。只要任一字段为空,无论工单看起来多么活跃,该发现都不处于管控之下。
结果责任人与执行人
修复责任人对结果负责:站得住脚的关闭、获得批准的例外或升级处理。这个人不一定是编写补丁的开发人员。在假设的例子中,修复由一名后端工程师完成,但“移动端后端是否也受影响”这个问题不属于任何人。为每个发现指定一名责任人,并分别记录执行人和验证人,就能消除“人人都以为别人检查过”的空档。
有效期与复核触发条件
状态是关于某一时刻的陈述。凡是临时性的事项都需要有效期:补偿性控制、风险接受、推迟的修复。复核触发条件是使先前假设失效的事件:触及受影响组件的版本发布;内部服务变为可从互联网访问;有新证据表明该弱点在真实攻击中被利用;责任人变更;补偿性控制发生变化;或改变信任边界的架构变更。日期和触发条件由组织自行确定,只需在需要之前写下来。
缺乏管控时修复为何失败
最常见的失败模式是:发现被关闭,是因为代码变更已合并,而不是因为已证明漏洞行为消失。没有依据既定要求进行复测,关闭只是一种断言而非证据,组织也无法区分真正的修复与不完整的修复。
第二种模式是治标不治本。CWE Top 25 项目将其 2025 年榜单描述为突出了其数据集中 CVE 记录背后最严重、最普遍的弱点,并指出理解根本原因有助于消除整类缺陷,并以内存安全和注入为例。如果团队只修补一个注入点,而底层的查询拼接模式依然存在,同样的弱点会在别处再次出现。
第三种模式是要求不明确。ASVS 提醒,要求标识符可能在不同版本之间变化,建议在每次引用时附上版本号,例如 v5.0.0-1.2.5。当工单引用没有版本的要求或含糊的描述时,开发人员、测试人员和审计人员会各自理解目标,关于是否关闭的争议便不可避免。
另外两种模式源于结构缺失:没有责任人和复核日期的发现会悄无声息地老化;后续版本发布后没有回归检查,一个已正确关闭的发现可能在无人察觉时卷土重来。这些更多是流程设计问题而非工具问题,详见我们关于基于证据的漏洞管理流程的指南。
重复实例与共同根本原因
有两种情况在报告中看起来相似,但需要不同的处理:同一漏洞出现在多个系统上,以及不同的发现源于同一个根本原因。
一个发现,多个受影响系统
重复实例是指同一漏洞行为出现在多个位置:多台主机运行着同样配置错误的服务,同一端点同时由 Web 后端和移动端后端暴露,或者同一缺陷存在于不同租户或环境中。一种有效的做法是设一个父级发现,并为每个受影响实例建立子记录,各自有状态和证据。只有当每个已知实例都已验证修复或被已批准的例外覆盖时,父级发现才能关闭。因为第一个实例通过复测就关闭父级发现,正是例子中漏掉移动端后端的原因。资产清单变化时应复核实例清单,因为同一组件的新部署就是一个新的潜在实例。
类别层面修复与部分修复
共同根本原因则不同:多个症状各异的发现可追溯到同一种模式,例如用字符串拼接数据库查询,或缺少集中的授权检查。CISA 安全设计警报聚焦于消除整类缺陷,包括跨站脚本、操作系统命令注入和目录遍历。由此得出一条实用规则:将类别层面的修复作为一个高优先级工作项,而不是若干互不相关的工单,但仍要依据每个原始发现自己的测试用例分别验证。
部分修复只解决了部分漏洞行为:只校验了一个参数而相邻参数没有;读取时检查授权而更新时没有;或修复已在生产环境部署,却未部署到可从外部访问的预发布副本。应将其记录为部分修复并注明剩余范围。在剩余部分得到修复、在例外框架下得到缓解或被正式接受之前,该发现保持未关闭状态。
不依赖通用评分的优先级排序
当不同信号保持各自独立时,优先级排序效果最好。CVSS 表达技术严重性。由 FIRST 维护的 EPSS 估计某个漏洞在未来 30 天内被利用的概率,它并不衡量业务影响。已观察到的利用是另一类证据:除 Top 25 外,CWE 项目还发布了 2025 年 CWE Top 10 KEV 弱点榜单,依据 CISA 已知被利用漏洞目录对被积极利用的弱点进行排名,另附差点入选的弱点清单,并指出命令注入等弱点会吸引攻击者的关注。暴露程度描述资产的可达程度。业务影响描述这一具体资产遭受攻击时组织将会损失什么。
并不存在能为所有组织正确合并这些信号的通用公式或阈值。我们建议(并非任何来源的强制要求)的做法是:分别记录每个信号,由指定责任人记录排序决定。已知被利用、暴露程度高、严重性高且业务影响严重同时出现的发现自然优先;信号相互矛盾时,书面理由最为重要。更详细的方法见我们关于基于风险的漏洞优先级排序的文章。
他人可重复的验收标准
关闭决定的质量取决于其标准。公开参考资料各有作用。OWASP Top 10 与 CWE Top 25 描述通常出现什么问题及其原因;ASVS 与 WSTG 说明应验证什么以及如何测试;NIST SP 800-115 与 NIST CSF 2.0 将测试和修复置于风险管理之中;CISA 安全设计资料关注制造商责任和采购;MDN 记录了许多 Web 修复所依赖的 HTTP 机制。
ASVS 为测试技术安全控制提供基础,并为安全开发提供要求清单。其主要目标是借助一个商业上可行的开放标准,统一 Web 应用安全验证的覆盖范围和严格程度。因此,修复的验收标准可以是某条具体的 ASVS 要求,而不是测试人员的个人判断。本文引用的是 ASVS 5.0.0;要求清单以 CSV、JSON 等机器可读格式发布,可以导入工单系统,而且每次引用都应注明版本。
OWASP 将 WSTG 描述为面向 Web 开发人员和安全专业人员的领先安全测试资源。4.2 版是一个已发布的带版本号的版本。在复测记录中注明 WSTG 测试引用及所用版本,可以让他人日后重复同一检查并得到可比的结果。
本文引用的是 OWASP Top 10 的 2025 年版,它被描述为标准的安全意识文档,是关于 Web 应用最关键安全风险的广泛共识。它有助于对发现分组并与管理层沟通,但并不是验证清单;单个修复的验收应对应更细粒度的要求,例如 ASVS。
MDN 的 HTTP 参考文档将内容安全策略(Content Security Policy)描述为一种响应头,可帮助检测和缓解包括跨站脚本和数据注入在内的某些攻击,并将 HTTP Observatory 列为帮助安全配置网站的工具。因此,响应头层面的修复可以依据文档化的行为进行验证,而不是想当然。
补偿性控制与限期例外
并非每个发现都能立即从根本上修复。为此有两种管理机制,二者都需要比普通修复更严格的管控,因为发现最容易在这里消失。
缓解不等于修复
补偿性控制在不消除弱点的情况下降低被利用的可能性或影响:过滤规则、通过功能开关停用的功能、网络限制或额外监控。快速的点状修复和缓解措施能减少眼前的暴露,但可能未触及根本原因;类别层面的修复耗时更长,但按照 CWE Top 25 与安全设计的思路,可以防止复发。许多团队将短期缓解措施与可跟踪的长期修复结合起来,并对两者都进行验证。缓解措施本身也要测试:换一种编码就能绕过的过滤规则不能算控制。生效期间,状态为“已缓解”而非“已关闭”,并注明有效期和撤除条件。
会到期的例外
风险例外,即正式风险接受,是在规定期限内保留已知弱点的决定。它应由对业务风险有决定权的人批准,而不是由原本需要修复它的工程师批准。例外应记录范围、理由、所依赖的补偿性控制、批准人、有效期和复核触发条件。到期时,应以新的决定续期、转为修复工作或升级处理,绝不能悄无声息地自动延续。接受风险是关闭工作项,而不是修复的证据,因此报告中应将两者分开。某项例外在合同或监管层面是否可以接受,是组织及其顾问的问题,而不是流程能回答的问题。
复测证据与关闭决定
验证是修复管控的核心。只有在经授权的复测证明原始测试用例不再成功且相关要求得到满足之后,或在已批准的例外记录在案之后,发现才能关闭。NIST SP 800-115 强调每种测试技术的优点和局限,因此复测方法必须审慎选择:自动化检查可以确认安全响应头,而授权缺陷通常需要人工验证。
复测能证明什么,不能证明什么
复测是在既定条件下验证一项具体修复:构建、环境、配置、用户角色、数据和日期。它不能证明风险永久消失,对范围外的漏洞也无从说明,这就是条件必须写进记录的原因。复测还应横向检查:如果弱点源于共享组件或编码模式,验证人应在授权范围内检查其他使用位置。CWE 根本原因映射让一次复测变成对整类缺陷的检查。技术层面的内容,包括如何设计真正检验修复的复测用例,见我们关于渗透测试修复验证的指南。
复测记录包含什么
一份合格的复测记录应包括原始发现编号及 CWE 映射;带版本的要求或测试引用,例如 ASVS v5.0.0 标识符或 WSTG v4.2 测试引用;构建、环境和日期;方法,即自动化、人工或两者结合;结果,即已修复、部分修复、未修复或风险已正式接受;以及验证人和批准人姓名。审计人员或新成员应能在不重复评估的情况下理解关闭的理由。
左右滑动查看对照
| 修复类型 | 足以支持关闭的证据 | 不够充分的证据 | 需要记录的条件 |
|---|---|---|---|
| 针对注入或授权缺陷的代码修复 | 重复原始测试用例且不再成功;范围内的相邻参数和端点已检查 | 已合并的拉取请求、无关的单元测试通过、工单标记为完成 | 构建、环境、角色、测试数据、验证人 |
| 配置或响应头变更 | 每台受影响主机的响应符合文档化行为,例如预期的内容安全策略 | 代码仓库中的配置文件,但没有部署证明 | 主机、地址、日期、方法 |
| 针对共同根本原因的类别层面修复 | 每个原始发现都已复测,并抽查范围内该模式的其他使用位置 | 修复了共享库,但未检查调用它的服务 | 库版本、已检查的调用方、剩余实例 |
| 补偿性控制 | 直接测试该控制,包括绕过尝试;状态保持为已缓解 | 规则未经测试即部署,或状态被改为已关闭 | 有效期、撤除条件、关联的长期修复 |
| 已批准的例外 | 签署的批准,包含范围、理由、补偿性控制和有效期 | 口头同意,或工程师以“已接受”为由关闭工单 | 批准人、有效期、复核触发条件 |
关闭决定可以表述为一个简短、可重复的流程:
- 记录每个发现一条记录:状态、CWE 映射、受影响实例、带版本的验收标准和结果责任人。
- 修复尽可能在根本原因层面修复;缓解措施和部分修复应注明剩余范围和有效期。
- 复测在书面授权和既定条件下重复原始测试用例,并检查范围内该模式的其他使用位置。
- 决定仅凭行为已改变的证据或已批准的限期例外关闭;否则保持未关闭或部分修复状态。
- 观察在复核触发条件出现时及版本发布后重新检查,行为再现时依据原始记录重新打开。
回归、重新打开与变更触发检查
关闭并不是记录生命周期的终点。后续版本可能通过重构、依赖更新或复制的代码重新引入漏洞行为。在可行时,应把原始测试用例转化为回归检查,在受影响组件每次变更时运行,并把重大变更视为重新开展人工测试的触发条件,详见我们关于变更触发渗透测试的指南。
当行为再次出现时,应重新打开原始记录,而不是另建一张毫不相关的新工单。这样可以保留根本原因、先前的证据以及当初准予关闭的条件。重新打开并不一定说明先前的关闭是错误的;对于当时所测的构建,它可能是正确的。
衡量关闭是否可信的指标
NIST CSF 2.0 的定位是帮助组织理解并改进网络安全风险管理,并提供配置文件作为描述现状和目标状态的模板。修复指标可以自然地纳入此类配置文件,作为进展的证据,但具体指标和目标由各组织自行确定。
我们建议的有用指标包括:按严重性和存续时间统计的未关闭发现;凭已验证复测证据关闭的比例;关闭后重新打开的比例;从报告到验证修复所需时间;共享同一 CWE 根本原因的发现数量;以及已过有效期的生效例外和缓解措施。重新打开率尤其能说明问题,因为它衡量关闭决定是否可信。
指标可能被操纵。统计已关闭工单奖励的是关闭行为,而非安全本身。将指标权重向已验证的关闭和反复出现的弱点类别倾斜,可以让关注点保持在结果而非活动上。
权衡与局限
自动化与人工判断:自动化重新扫描易于扩展,适合配置问题,而业务逻辑和授权缺陷需要人工测试。NIST SP 800-115 对每种技术局限性的强调,同样适用于复测与初始测试。
内部验证与独立验证:内部团队熟悉系统,可以持续复测;独立验证方能增强审计人员、客户和管理层的信任。合适的平衡取决于监管义务、内部能力和系统的关键程度。
参考资料的年代:NIST SP 800-115 发布于 2008 年 9 月,取代了 2003 年的 SP 800-42。其规划、分析和缓解的原则仍然有用,但技术层面的细节应以 ASVS 和 WSTG 等现行资源加以补充,并注明实际使用的版本。
流程的局限:渗透测试、复测或修复管控流程都不是认证、鉴证或保证意见。它们提供的是在特定条件下关于特定行为、有明确边界的证据。
如何选择外部复测或验证服务商
在内部流程清晰之后,外部帮助才有意义。CISA 的按需安全(Secure by Demand)指南面向软件客户的采购环节,其安全软件部署(Safe Software Deployment)指南强调稳健的测试和度量。两者都可以转化为向复测和修复验证服务商提出的问题。
应询问:发现是否映射到 CWE 和带版本的 ASVS 要求;复测是否包含在内,合同中是否明确了轮数和时限;每次复测产出什么格式的证据;复测是否采用与原始测试相同的方法;部分修复、重复实例和正式风险接受如何报告;以及每次复测是否都在书面授权和界定范围内进行。应索取一份匿名化的复测报告样本,而不是接受笼统的说法。
评估软件供应商时,CISA 的安全设计承诺(Secure by Design Pledge)以及参与制造商的进展报告是合理的评估依据,但参与本身并不能证明产品安全。CISA 还指出,安全的产品应默认提供多因素认证、日志记录和单点登录,且不额外收费。日志记录对修复管控很重要,因为它有助于确认修复已生效,并使针对旧弱点的利用尝试可被发现。
关闭管控的实用步骤
以下每一步都应有明确的责任人、文档或工具作为支撑:
- 将每个验收标准定义为带版本的要求,例如 ASVS 标识符。
- 指定责任人,分别记录严重性、利用证据、暴露程度和业务影响,并记录排序决定。
- 将发现映射到 CWE 根本原因,列出受影响实例,并对同因发现进行归组。
- 尽可能修复根本原因;为缓解措施、部分修复和例外设定有效期和复核触发条件。
- 在书面授权下使用有文档、带版本的方法,并在既定条件下进行复测。
- 记录可供第三方确认关闭的证据。
- 跟踪重新打开率、过期例外和反复出现的弱点类别。
- 确定哪些系统需要独立验证,并在 CSF 2.0 配置文件中复盘进展。
如果某一步无法落实到具体的人员、工件或系统,应在投入更多扫描或测试之前先弥补这一缺口。如果您正在准备复测或新的评估,并希望事先约定系统、访问权限、限制条件和预期证据,可以与 Pentest.red 一起准备渗透测试范围。
结论:关闭是证据,而非工单状态
有效的修复管控建立在公开参考资料所支持的几个理念之上:修复依据明确且带版本的要求进行验证;由根本原因而非症状驱动修复,CWE Top 25 背后的思路也说明了这一点;优先级排序把严重性、利用概率、已观察到的利用、暴露程度和业务影响区分开,而不是压缩成一个数字。结合限期例外和符合 CSF 思路的指标,组织就能向审计人员、客户和管理层证明:在既定条件下,某个具体漏洞已不再表现出原有行为,而不只是工单已关闭。外部验证只有在明确授权下提供同等质量的证据时,才能真正创造价值。
PENTEST.RED
讨论渗透测试范围与报价
首先明确系统、访问权限、限制条件和预期证据。
本文以深入研究为基础,经过编辑整理,注重清晰表达和实际应用。