跳到正文
>_ITDITDWeb 安全平台

安全指南

漏洞(CVE)处置实务:彻底修复,并持续监控复发

在中小规模团队把依赖库的漏洞(CVE)「彻底修复掉」的实务步骤。以扫描→修复→隔离/移交→监控这套『完成的4个定义』为骨架,讲解如何用变化检测避免告警疲劳、不要轻信 HTTP 200、不要让修复被覆盖(local→push→deploy)、跨大版本要在与生产相同的环境里构建验证等现场要点,并结合本站的运维视角加以说明。

发布于 2026-06-11 更新于 2026-06-11 3 分钟阅读

对象:人手不多、同时运维多个 Web 应用(框架混用),想把依赖库的漏洞(CVE)处置「认真彻底地修一次」的人。这里不讲攻击手法,只讲修好、让它不会消失、并持续监控为止的实务。容易成为导火索的事故示例,可参考 放任已公开的RCE导致被恶意刷费的经历

本站的视角:越小的团队越能靠『两个机制』守住

人手少的团队,真正管用的不是花哨的工具,而是两条纪律。①自动的变化检测(只对新增的漏洞报警)②local→push→deploy(生产端只接收,不编辑)。本站也是同样的思路,把依赖审计(pnpm audit)放在每次部署前+每日 cron 里跑,向生产端则只用 push-to-deploy 来分发。不要把它当成一次性的修复事件,而要倒向放好一个会报警的机制并持续运转的运维方式,这反而是最便宜、最持久的。

先把完成的「4个定义」固定下来

这是为了不让人随便说「搞定了」的刹车。先约定好:在这四点齐备之前都算未完成。

① 扫描

用数字掌握现状

② 修复

根治非dev的严重/高危

③ 隔离/移交

修不了·孤立的要明示

④ 监控

加上每日变化检测

漏洞处置的完成=四点一套。缺一项就会留下『以为修好了』的窟窿。

① 扫描:把现状变成「数字」

首先,用机器掌握「哪里有什么」。手动的不定期检查一定会中断。

1

自动探索锁文件并扫描

查找 composer.lock / package-lock.json / pnpm-lock.yaml,每天用 OSS 扫描器(osv-scannerpnpm audit)跑一遍。只是读锁文件,负载极轻。
2

要知道严重度不是『一个数字』就能定

同一个漏洞,在 CVSS 里是高(例如7.5)、但厂商细查后是中,这很常见。CVSS 是机器算出的,容易高估。要决定按哪个基准来划阈值,并让团队所有人都共享『现在用的是哪一个』(→ 什么是CVSS)。再与是否实际被利用(KEV)相乘,得出优先级。
3

噪声不是『无视』而是『有依据地排除』

仅用于测试/构建的 dev 依赖往往不会进入生产打包,多数情况无实害。在扫描器的分组判定里把 dev 从通知中排除,同时把为什么排除记进台账。让自己处于日后能解释「这个不是没修吗?」的状态。

② 修复:不要对症疗法,要「根治」

止血(对症疗法)和根治是两件不同的工作。两者都做了才算结束。

只做对症疗法(止于围堵)

  • 用反向代理只挡掉「看起来像那样」的请求
  • 因为症状停了就以为「处置完成」
  • 脆弱的依赖原封不动RCE等仍然存活

根治(正确)

  • 把脆弱的依赖更新到修复版,堵住窟窿本身
  • 更新后,用日志确认征兆是否消失
  • 把止血和根治当作两件事都做

跨大版本要『在推上生产前先构建验证』

和打补丁不同,跨大版本(框架14→15、UI工具4→6 等)会伴随破坏性变更。盲目升级而导致生产构建失败是最糟的。把改完的源码放到与生产相同的运行时(同样 Node/PHP 版本的容器)里,等构建/类型检查完全通过后再 push。失败的报错要一个一个解决(同步→异步化的 codemod、CSS 的多行 class、类型命名空间被废弃 等)。若采用旧容器仍在运行的结构,失败时也能不停机地回切。

把修复的「持久性」也包含进来才算完成

内容哪怕100分,只要下一次部署就被覆盖,也是0分。这是最容易踩的坑。

1

不要在生产的工作树里直接commit

在生产直接 commit,会与中央仓库的历史分叉,在下一次部署(pull / checkout -f)时被覆盖,修复就消失了。生产是『接收部署结果的地方』,不是用来编辑的地方。
2

务必统一为 local→push→deploy 的单向流动

编辑在本地→commit→push→(生产端)pull/自动部署。即便不得已在生产上做了确认性的改动,也务必回退到本地、重新 push(→ 让生产端只接收的做法)。
3

不要把 HTTP 200 当成『正常』

在共享托管等环境下,即使是致命错误也可能返回 200。验证务必用实际内容来做——正文里期望的标题/文本是否被渲染出来(curl | grep)、错误日志里是否出现新条目、连依赖 DB 和带参数的动态路由都要走一遍。由于缓存可能让生效变慢,要隔一段时间或清缓存后再看。

③ 隔离/移交:把修不了的东西「明示」出来

不一定所有问题都能马上修好。诀窍在于:对修不了的、归属他人管辖的、已经不用的,不要含糊其辞

1

孤立·EOL 代码要『在删除前先隔离』

已经不再对外提供的旧源码(EOL 框架等),不要直接删除,而是用重命名来隔离,并留下写明「何时·为何隔离·原本的发布位置」的标记。也要把它移出扫描对象。『删除』不可逆,而『隔离』可以还原、来龙去脉也能留存。
2

先确定确实无人引用,再动手

追查反向代理配置、构建配置、挂载,确认没有任何地方在引用之后再隔离。掐断误被重新发布的事故种子。
3

修不了/他人管辖的要明示移交

自己修不了的,不要放任,而要明示『交给谁·什么内容』地移交出去。不把未处置变成『看不见的放任』,正是盘点的价值所在。

④ 监控:加上每日「变化检测」才算完成

走到这一步,最后放上会报警的机制。没有它,就算辛苦修好了,也察觉不到复发。

不是『把全部每天都报』而是『增加了才报』

把扫描结果与上次取差分(state file)比较,只在出现新增的严重/高危时才通知。每天都收到相同内容,很快就会被无视(告警疲劳)。通知汇总成一封邮件(新增·已解决·现状),用 cron 每日跑。哪怕是共享服务器,靠一个扫描器二进制+cron 也足够运转(负载是数毫秒量级·搭配 nice 就更稳妥)。

差分
只通知增加的漏洞=不会疲劳
每日
用 cron 持续运转
一封
汇总新增·已解决·现状
到④
加上监控才算完成

盘点时会一并冒出来的「秘密」和「密钥」

在彻底修复 CVE 的过程中,常常会连依赖以外的窟窿一起被发现。最有代表性的有两个——遗忘在公开目录里的秘密文件(webroot 里放着旧 token,若源自共用模板就所有机器都有同一个窟窿)和交给可能被入侵的临时环境的 root 密钥。两者都是会造成「一处泄露就全盘皆失」的典型,所以要在和 CVE 处置相同的盘点时机一并检查(这两个各自都值得单独深挖)。秘密的基础可参考 秘密的安全保管最低限度检查清单

接下来读

FAQ

Q漏洞处置做到什么程度才算『完成』?
A

四点齐备才算完成。①用扫描把现状变成数字②修复了非dev的严重/高危③对修不了的、归属他人管辖的、已孤立的代码做了明示的隔离/移交④加上了每日变化检测(能捕捉复发与新增的监控)。尤其在加上④之前都不算完成,因为依赖明天又可能变得脆弱。

Q每天扫描不会被告警搞得疲惫吗?
A

『把全部内容每天都报一遍』很快就会被无视。要与上次结果取差分,只在出现新增的严重/高危时才通知,这就是『变化检测』。不每天发送相同内容,反而是最能长期坚持下去的设计。

Q明明修好了,为什么又退回到脆弱状态?
A

在生产的工作树里直接commit,会在下一次部署(pull 或 checkout -f)时被覆盖,修复就消失了。务必统一为 local→push→deploy 的单向流动,让生产端『只接收』。修复内容哪怕完美无缺,只要会被覆盖的运维方式,成果就是零。