一个季度修了 2400 个漏洞,高危还剩 180 个没动——这是我在一家制造企业看到的真实状态。安全团队每周出报表,数字清清楚楚,但没人被追责,因为这张报表里没有一个数字是用来考核任何人的。
问题不在工具,也不在流程图画得好不好。这套闭环缺的是三样东西:SLA 有没有按风险分级定死、每个环节有没有可判定的验收标准、数据有没有落到具体的人头上。
这篇讲这三件事怎么落。工具部分用 DefectDojo 举例,但换成任何平台思路一样。想先看「怎么把研发说服、怎么催」的,可以看另一篇:漏洞整改推不动?我把 3 年踩坑做成 1 张责任矩阵 + 12 条话术——那篇讲人,这篇讲流程和数据。
一、先算清楚:你现在这条流水线卡在哪一环
在改流程之前,先做一次基线测量。不然改完没法证明有效。
需要量的只有四个数,从现有台账里就能挖出来:
| 指标 | 怎么算 | 说明 |
|---|---|---|
| 平均发现到派单时长 | 派单时间 − 发现时间 | 超过 3 天说明归集环节在人工搬数据 |
| 平均派单到修复时长 | 修复时间 − 派单时间 | 按高危/中危/低危分开算,混在一起没意义 |
| 一次修复通过率 | 首次复测通过数 ÷ 复测总数 | 低于 70% 说明整改指导不到位 |
| 逾期率 | 超 SLA 未闭环数 ÷ 应闭环数 | 这是唯一能拿去考核的数 |
我们那次基线测出来是:派单平均 4.2 天、高危修复平均 38 天、一次通过率 61%、逾期率 43%。四个数里最刺眼的是 4.2 天——漏洞在台账里躺着的时间比在研发手里的时间还长。
测完这四个数,你就知道该先动哪一环。上面这组数据指向的是归集自动化,不是催办。
二、SLA 怎么定:不是统一 7 天,也不是照抄监管
最常见的错误是「高危 7 天、中危 30 天、低危 90 天」一刀切。这套数字抄自监管要求,但监管给的是下限,不是你的运营目标;而且它只看严重程度,不看可利用性。
我用的定法是两个维度交叉:能不能被远程直接利用×资产暴露面。
先看第一个维度。同样是 CVSS 9.8,一个需要认证才能打的洞,和一个匿名就能 RCE 的洞,实际风险差一个数量级:
| 可利用性 | 判定标准 | 处置时限(对外暴露资产) | 处置时限(纯内网资产) |
|---|---|---|---|
| 已被在野利用 | 有公开 EXP 或有实际攻击流量 | 24 小时内临时缓解,7 天内根治 | 3 天内缓解,14 天内根治 |
| 可远程未授权利用 | 无需账号、可从网络直达 | 3 天内缓解,14 天内根治 | 7 天内缓解,30 天内根治 |
| 需认证或需交互 | 要有账号,或需用户点击 | 14 天内 | 30 天内 |
| 本地提权 / 信息泄露 | 需本地权限或仅泄露低敏信息 | 30 天内 | 60 天内 |
| 配置类、加固建议 | 不构成直接可利用路径 | 90 天内或随版本迭代 | 90 天内 |
「缓解」和「根治」要分开定,这一点很多人漏掉。缓解是指在 WAF 加规则、在安全组封端口、在网关摘流量这类不改代码的动作;根治才是升级组件或改代码。给业务一个能当天做的动作,比逼它明天上线一个补丁现实得多。
第二个维度是暴露面。判断标准只有三条:这个资产有没有公网 IP、有没有从公网可达的入口(哪怕是通过网关转发)、上面有没有对外业务数据。三条中一条成立就算对外暴露。
这张表定下来之后,一定要写进制度并让业务负责人签字。SLA 没被签过,就永远只是安全团队的单方面要求。
三、每个环节要有可判定的验收标准
流程图画 8 个环节不难,难的是每个环节「做完了没有」由谁、按什么标准判定。下面是我实际在用的判定表:
| 环节 | 完成判定 | 谁判定 | 留什么证据 |
|---|---|---|---|
| 发现 | 有明确的资产归属(系统 + 责任人) | 扫描平台自动匹配资产台账 | 扫描任务 ID + 原始报告 |
| 归集 | 同一漏洞在多个工具的结果已合并 | 平台去重规则自动判 | 关联的多个 issue ID |
| 定级 | 已按「可利用性 × 暴露面」定级,不是只取 CVSS | 安全团队复核 | 定级依据字段(含利用条件说明) |
| 派单 | 已落到具体的人,不是落到部门 | 系统按资产责任人自动派 | 工单号 + 责任人 |
| 整改 | 提交了修复说明 + 自测记录 | 研发提交,安全复核 | 修复 commit / 变更单号 |
| 复测 | 在原漏洞点复现失败,且同类接口抽测通过 | 安全团队 | 复测记录 + 复现命令 |
| 归档 | 根因分类已填(代码/组件/配置/流程) | 安全团队 | 根因标签 |
| 复盘 | 同类问题是否已批量排查 | 安全团队 + 研发负责人 | 排查范围与结论 |
这张表里最容易糊弄的是「复测」和「归档」。
复测只测原来那个点是不够的。SQL 注入修了这一个参数,同一个接口的其他参数、同一个服务的其他接口,大概率是一样的问题。复测时至少抽同类接口 3 个,这是我加进去的硬要求,加上之后复发率从 21% 降到 7%。
归档时根因必须分类。不分类的话,你永远不知道漏洞是从哪冒出来的——是组件版本旧、是编码规范没落实、还是发布流程漏了检查。分类之后按季度统计,你会发现某一类占了一半以上,那一类才是该投入的地方。
四、把 SLA 变成平台里的硬约束
制度写在文档里没人看,写进系统才会生效。DefectDojo 里对应的是 SLA Configuration,按严重级别配天数,超时会自动标记。
配置的核心是按产品分别配,不是全局一套。因为对外业务和内部系统的容忍度本来就不一样。
# 先建 SLA 配置(按产品维度区分对外/内网两套) curl -X POST "https://dojo.example.com/api/v2/sla_configurations/" \ -H "Authorization: Token $DOJO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "对外业务-高危", "description": "公网可达资产,可远程未授权利用", "critical": 1, "high": 3, "medium": 14, "low": 30 }' # 把产品绑定到对应 SLA 配置 curl -X PATCH "https://dojo.example.com/api/v2/products/12/" \ -H "Authorization: Token $DOJO_TOKEN" \ -H "Content-Type: application/json" \ -d '{"sla_configuration": 3}'第二步是把工单推到研发日常用的地方。没人会为了看漏洞专门登录一个平台,但所有人都会看自己的 Jira 待办。
# 开启 Jira 联动:issue 创建时自动建 Jira 单,状态双向同步 curl -X PATCH "https://dojo.example.com/api/v2/jira_instances/1/" \ -H "Authorization: Token $DOJO_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "configuration_url": "https://jira.example.com", "username": "dojo-bot", "password": "'"$JIRA_TOKEN"'", "default_issue_type": "Bug", "issue_key_field": "jira_issue" }'推 Jira 时有个细节必须处理:漏洞标题要写成研发能看懂的一句话。平台默认标题是「SQL Injection in /api/user/query」,研发看到只知道自己被扫了。改成「/api/user/query 的 id 参数存在 SQL 注入,可用单引号报错验证」——带上位置、类型、验证方式,研发不用来问你第二遍。
第三步是去重。同一个组件漏洞会在主机扫描、容器扫描、代码依赖扫描里各报一次,不去重的话台账会被灌成三倍,逾期率也跟着失真。
DefectDojo 有 deduplication 配置,按 hash_code 判重。我的设置是:
- 同一产品内,相同 CVE + 相同组件 → 合并(这条必开)
- 同一产品内,相同 URL + 相同漏洞类型 → 合并(这条要看情况,多参数注入会被误合)
- 跨产品不合并(不同系统的问题必须分开追)
第三条容易理解错。有个集团客户的三个子系统共用一套基础镜像,一个基础镜像的漏洞被合并成了一条,结果只有一个子系统改了,另外两个一直带着。跨产品合并是台账失真最常见的原因。
五、数据给谁看:三张报表,三种口径
同一批数据,给研发、给业务、给领导看的东西完全不一样。用一张表糊弄所有人,结果是所有人都看不懂。
给研发的:待办清单。只列他名下未闭环的,按 SLA 剩余时间排序,每条带复现步骤和修复建议。不要放统计图,他不需要。
给业务负责人的:逾期台账。只列他这条业务线超期的,按「超期天数 × 资产重要性」排序。关键是要有对比——他这条线和其他业务线的逾期率对比,这是唯一能形成压力的数字。
给领导的:一页纸。三个数就够:
| 指标 | 本期 | 上期 | 变化 |
|---|---|---|---|
| 高危平均修复时长 | 12.4 天 | 19.8 天 | ↓ 7.4 天 |
| 高危逾期率 | 8% | 23% | ↓ 15pt |
| 一次修复通过率 | 84% | 61% | ↑ 23pt |
再加一句结论:「高危漏洞平均修复时长从 19.8 天降到 12.4 天,逾期率从 23% 降到 8%,主要来自对外业务资产启用自动派单和 Jira 联动。」
领导要的不是漏洞总数,是趋势和你做了什么导致了这个趋势。只报「本期发现 xxx 个、修复 xxx 个」,他无法判断你在变好还是变坏。
六、复现单怎么写,决定研发改得快不快
同一个漏洞,工单写得清楚和写得含糊,修复时间能差三倍。研发不是不想改,是他拿到「存在 SQL 注入」这句话,得先花半天搞清楚是哪个接口、哪个参数、怎么验证改好了没有。
我把工单的必填字段固定成五项,缺一项安全团队不允许提交:
| 字段 | 写什么 | 反例 |
|---|---|---|
| 位置 | 完整请求路径 + 参数名 + 参数在 URL/body/header 哪一处 | 「用户接口存在注入」 |
| 验证方式 | 一条能直接复制的命令或请求,跑完就能看到现象 | 「用单引号测试」 |
| 现象 | 预期结果与实际结果分别是什么 | 「存在注入」 |
| 影响 | 能读到什么数据、能执行什么操作 | 「高危漏洞」 |
| 修复建议 | 具体到用什么函数、加什么校验 | 「请修复」 |
一条合格的复现记录长这样:
# 位置:GET /api/user/query 的 id 参数(URL 参数) # 验证:把 id 改成 id=1' 观察响应 curl -s "https://app.example.com/api/user/query?id=1%27" | head -20 # 现象:返回体出现 SQL 语法错误,MySQL 版本为 5.7.32 # 进一步验证(布尔盲注,判断是否可绕过滤) curl -s "https://app.example.com/api/user/query?id=1%20and%201=1" | wc -c curl -s "https://app.example.com/api/user/query?id=1%20and%201=2" | wc -c # 两次返回长度不同(如 4821 与 1203),确认条件可控
「影响」这一项要写业务语言,不写 CVSS。写「可读取 t_user 表全部字段,含手机号与身份证号」,不写「CVSS 8.6 高危」。研发和业务负责人对后者没有感知,对前者有。
「修复建议」也要给到能落地。SQL 注入给「改用参数化查询,不要拼接字符串」,比给「请做输入过滤」有用得多——后者会诱导研发写黑名单过滤,那玩意绕得过去。
七、升级机制:什么时间点该找谁
催办不是靠喊。定好时间点,到点自动升级,避免安全团队天天当坏人。
| 触发条件 | 升级到 | 动作 |
|---|---|---|
| 高危派单 24 小时无响应 | 研发组长 | 平台自动发 IM 提醒,附复现单链接 |
| 高危超期 3 天 | 业务负责人 | 邮件 + 周会通报,要求给排期 |
| 高危超期 7 天 | 业务线分管领导 | 走风险上报,附「若被利用的业务影响说明」 |
| 对外暴露资产的高危超期 | 直接上风险委员会 | 不等 7 天,这类不给你试错时间 |
| 中危超期 30 天 | 业务负责人 | 计入季度考核,不单独升级 |
这套机制的关键是自动。平台到点自动发、自动升级、自动留痕,安全团队只负责维护规则,不负责天天催人。一旦变成人工催,你就会陷入「催了改、不催不改」的循环,而且催得越多越没人当回事。
还有一条经验:升级要升级到「能调动资源的人」,不是「更大声的人」。研发组长调不动运维窗口,业务负责人能;业务负责人调不动预算,分管领导能。找错层级,除了多一次不愉快,什么都不会发生。
八、几个容易被忽略但会毁掉闭环的点
第一,资产归属不准,整条链路就空转。扫描器扫到的 IP 匹配不到责任人,只能派给运维,运维再转给研发,两天就这么过去了。上线前必须先把资产台账和扫描范围对齐,这一步没有捷径。台账怎么建,企业网络拓扑图怎么画才不过期 那篇里的资产发现脚本可以直接拿来用。
第二,风险接受要有出口。总有一部分漏洞业务上确实修不了(老系统、供应商不再维护)。没有正规的风险接受流程,这些漏洞就永远挂在「待整改」里,把逾期率抬到没法看。正确做法是走风险接受审批:业务负责人签字、写清补偿措施、设复查周期(一般 6 个月)。接受过的漏洞从逾期统计里剔除,但仍在台账里可查。
第三,别用漏洞数量做排名。按「发现漏洞数」排名,研发会倾向于少报、晚报;按「修复数量」排名,会倾向于挑简单的改。要排就排「逾期率」和「一次修复通过率」,这两个数没法刷。
第四,闭环不等于清零。目标不是台账归零,是「高危不过夜、中危不跨季」。追求全部清零的团队,最后一定会走向批量伪造修复记录。
九、三个月能推到什么程度
按我实际推过的节奏,给一个参照:
| 阶段 | 时间 | 做成什么 | 判断标准 |
|---|---|---|---|
| 一期 | 第 1 个月 | 资产对齐 + 自动派单 + SLA 上线 | 派单时长降到 1 天内,逾期率能算出来 |
| 二期 | 第 2 个月 | Jira 联动 + 去重 + 复测抽检 | 研发在 Jira 里就能看到并处理,复发率下降 |
| 三期 | 第 3 个月 | 度量报表 + 根因分类 + 风险接受流程 | 三张报表能自动出,根因分布有数据 |
一期最容易卡在资产对齐。有个加速办法:先只做对外暴露的那 20% 资产,跑通一整轮,拿着结果去要资源扩范围。这 20% 的漏洞占了实际风险的大头,也最容易拿到业务配合——因为业务自己也怕。
三期做完不要宣布「闭环建成」。漏洞管理没有建成的那天,只有运营得好不好的区别。数据一旦不更新,三个月后这张台账就变成了历史文件。
这个账号里还有几篇是同一条链路上的:安全基线落不了地 讲配置类问题怎么核查,一次挖矿入侵处置复盘 讲漏洞真被利用之后怎么处置。三篇连起来是一条完整的「发现 → 修 → 出事兜底」。