ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Dependency-Track大规模项目堆积故障排查与恢复-续篇:漏洞都去哪儿了

Dependency-Track大规模项目堆积故障排查与恢复-续篇:漏洞都去哪儿了 两万个项目堆成山续漏洞都去哪儿了上回说到我们删了一万五千个旧项目DT 服务满血复活。本以为可以功成身退结果第二天一早打开页面——漏洞数量0。欢迎收看大型连续剧《运维永不杀青》第二集。前情提要[上一集](两万个项目堆成山一次 Dependency-Track 服务雪崩的全记录)里我们的 Dependency-Track以下简称 DT被两万个堆积的项目活活累瘫健康检查连续失败一万五千多次才被发现。我们重启、备份、写脚本、删项目一气呵成。故事本该在删除完成成功 6671失败 61这一行画上句号。但运维的故事从来没有句号只有逗号。一、案发第二天漏洞集体失踪清理完成后的第二天例行检查。打开 DT 的 Dashboard准备欣赏劳动成果。Portfolio 漏洞0。面临风险的项目0。易受攻击的组件0。一整排零蛋整整齐齐仿佛在嘲笑我。要知道清理前这里显示的是一百六十多万条漏洞发现。一夜之间从百万富翁变成穷光蛋这剧情走向不对啊。第一反应删错了难道清理脚本把不该删的也删了先深呼吸。然后开始分层排查——这是血的教训换来的纪律数字归零不等于数据丢失先验证再恐慌。二、分层诊断是没算完还是真没了2.1 第一层指标缓存DT 的 Dashboard 不是实时查库而是读指标缓存。大规模删除后ProjectMetricsUpdateTask需要重新计算所有项目的指标计算完成前显示 0 是正常的。查日志指标任务在跑每 2.5 秒处理十几个项目。行等它算完。4137 个项目预计十几分钟。2.2 第二层真没了十几分钟后任务跑完了。再查——还是 0。这就不是缓存的事了。开始查数据库这里有一个关键认知表是什么当时数量VULNERABILITY全局 CVE知识库漏洞字典306,132COMPONENTS_VULNERABILITIES项目组件与漏洞的关联页面数字的来源0FINDINGATTRIBUTION漏洞发现归因0看到没30 万条漏洞记录安安静静地躺在知识库里一条没少。但哪个项目的哪个组件中了哪个漏洞的关联表空空如也。这就好比图书馆的书都在但借阅记录全没了——书没丢是关系没了。三、时光机3.6GB 备份再度立功关联表为空有两种可能清理时被误删了事故要背锅本来就没有历史遗留更尴尬怎么定性上备份。清理之前我们做过 3.6GB 全库备份此刻它就是时光机。把备份恢复到一个临时数据库容器里跑几条对照查询备份里的关联记录总数1,677,908 其中属于近 180 天项目我们要保留的的0 其中属于超 180 天项目我们删掉的的1,677,833真相大白那一百六十八万条漏洞发现全部挂在被删除的旧版本项目上。我们保留下来的四千多个近期项目在清理前就一条发现都没有。清理没有丢数据。它只是把一堆旧账本烧了——而那些我们想留的账本本来就是空白的。虚惊一场不是惊出第二场。四、更尴尬的真相分析器在长期罢工新问题浮出水面为什么近半年的项目一条漏洞都没分析出来难道我们的代码都完美无缺用过 Maven 的人都知道这不可能——Spring、log4j、fastjson 这些老朋友哪个不是背着几十上百个 CVE 的翻配置答案找到了内部分析器靠组件的 CPE 去匹配 NVD。而 CI 生成的 CycloneDX BOM 里Maven 组件只有 PURL没有 CPE。CPE 和 PURL 是两种不同的组件标识格式。分析器拿着 CPE 格式的钥匙去开 PURL 格式的锁开了半年一把也没打开。而那个能解决这个问题的开关——“对 PURL 组件启用模糊 CPE 匹配”——从来没被打开过。系统没有报错没有警告只是每天勤勤恳恳地导入 BOM、勤勤恳恳地分析、勤勤恳恳地得出零条结果。它不罢工它只是在无效加班。五、配置的语义恶作剧界面说启用数据库说排除找到开关打开它总行了吧没那么简单。在界面上勾选对 PURL 组件启用模糊匹配点保存——勾选框自己弹回去了。再勾再弹。像极了那个永远关不上的浏览器弹窗。一度以为是前端 bug。直到直接查了数据库才发现 DT 的配置属性玩了一手语义反转internal.fuzzy.enabled false ← 模糊匹配总开关关 internal.fuzzy.exclude.purl true ← PURL 组件被排除看懂了吗数据库里用的是“排除exclude”语义true表示排除掉而界面上写的是“启用”。同一个配置两张面孔。而且还有个联动逻辑总开关关着的时候子选项无法持久化——这就是勾选框自动弹回的原因。它不是 bug是你不配。正确姿势先开总开关再改排除项最后查库验证。永远不要只相信界面数据库才是老实人。六、墙外有墙情报源的连通性罗生门配置修好了顺手检查了一下漏洞情报源的同步状态——又发现问题。本地 NVD 知识库的最后同步时间九个月前。也就是说就算分析器一直在正常工作它用的也是九个月前的漏洞字典。查最新 CVE不存在的。为什么停了九个月连通性测试安排上目标结果NVD 主站和旧版 feeds403Cloudflare 按 IP 拦截NVD 官方 REST API200OSS Index可达GitHub Advisories可达同一堵墙拦住了旧路新路口却敞开着。NVD 官方日志里还贴心地留了句话“旧版 feeds 即将退役建议切换到 REST API 镜像。”官方都这么说了那就切。在配置页启用API 镜像模式申请一个免费的 API Key 填进去重启收工。理论上。七、补全行动4152 个项目的再教育回到漏洞补全。开启模糊匹配只对新导入的 BOM生效存量四千多个项目需要重新触发分析。DT 没有重新分析按钮。唯一的办法把每个项目的 BOM 导出来再重新上传一遍——上传动作会触发完整的分析流水线。写个脚本导出 → base64 编码 → 重传3 线程并发。听起来很简单执行起来三连坑。坑一Key 里的换行符脚本启动4152 个项目全部失败报错Invalid header value b...\n。排查半天最后发现是设置环境变量时引号跨了行API Key 的值里混进了一个换行符。HTTP 头里带换行服务器当场拒收。修复重新设置变量顺手给脚本加了.strip()——永远不要相信用户输入包括你自己。坑二KeyError: ‘bom’重跑又全部失败这次是KeyError: bom。手工调试才发现DT 4.11 的 BOM 导出接口直接返回 CycloneDX 文档本身没有{bom: ...}包装。脚本里那句json.loads(raw)[bom]对着空气取了个键。版本升级改了接口行为文档没说代码没变坑留给了运维。修复拿到原始内容直接编码上传。坑三跑的还是旧脚本改完代码重跑报错一模一样。一度怀疑人生。最后发现文件压根没更新成功后台跑的还是旧版本。从此立了个规矩启动后台脚本前先grep一下关键代码行确认文件真的是你以为的那个版本。三连坑填完脚本正式开跑。这次一路绿灯[4150/4152] 成功 4150 失败 0 完成: 成功 4152, 失败 0零失败。漏洞发现从 0 涨回五万多条一百多个项目重新挂上了有风险的牌子。数字没有回到一百六十八万——那是好事。旧的百万级数字是两年里每个构建版本重复计数的虚胖现在的五万条只统计活跃版本。健康的数据不需要虚高的排面。八、NVD Key 悬疑剧88 个字符的罗生门补全跑完回头处理 NVD 同步结果它给了个下马威NvdApiException: NVD Returned Status Code: 403Key 被拒。检查数据库里存的 Key长度88——而标准 NVD Key 是 36 位 UUID。粘错了我们当即断定还顺手分析了 88 位里的/、、“看这是 base64 字符明显不是 Key。”于是重新申请、重新粘贴、重新验证……折腾一圈后才发现真相DT 会把 Key 加密后存库。36 位明文加密后恰好是约 88 位的 base64 密文。那些可疑的 base64 字符是加密的正常产物。而我们中途还干过一件蠢事把数据库里的密文取出来当 Key 去调 NVD 接口——用加密后的乱码当钥匙开锁不开才怪。教训很简单验证配置是否生效看任务的实际日志别拿密文当凭证。真正的凶手是第一次确实粘错的凭证。把正确 Key 在宿主机实测 200 后重新填入重启容器。由于镜像任务是 24 小时周期调度当天已有执行记录重启不再触发全量同步要等次日凌晨的调度窗口自动执行。不急。这次钥匙已经配好了只等锁自己转。九、装上烟雾报警器第一集的结尾说过治标不如治本。这一集我们把报警器装上了健康检查脚本 每小时定时巡检DT API 是否存活项目总数是否超过阈值比如 6,000——上次就是堆到两万才崩的异常写告警日志一个小插曲脚本第一版用grep X-Total-Count提取项目数结果把 CORS 响应头也匹配进去了算出来项目数是Origin,。匹配加行首锚点问题解决。正则一时爽锚点保平安。十、这一集的教训数字归零先分层区分指标缓存没算完和关联数据真没了别一上来就写事故报告。知识库不等于发现VULNERABILITY表有 30 万条不代表项目有 30 万个漏洞。前者是字典后者是病历。备份是最好的时光机分不清删丢了还是本来没有恢复到临时库对比一下十分钟出真相。界面会说谎数据库不会尤其是带排除/启用语义反转的配置查库验证是唯一标准。沉默的失败最危险分析器空转了半年没有任何报错。给你的关键链路加个产出是否为零的监控吧。后台脚本启动前确认文件版本grep一下关键行两秒钟省两小时。密文不是凭证加密存储的配置不能取出来当原文用也不能拿明文长度做校验。写在最后这两集合起来是一个完整的连环案项目堆积压垮服务 → 清理恢复 → 暴露出漏洞归零 → 挖出分析器长期空转 → 顺带发现情报源断更九个月 → 补全数据、切换同步通道、装上监控。每一层问题都藏在上一层的阴影里。如果只修到第一层就收工我们会拥有一个健康但永远零漏洞的 SCA 平台——一个从不出漏洞报告的安全平台是安全的吗大概比不出报告更危险的是看报告的人以为它很安全。所以去检查你的关键系统吧。不只是检查它活着还要检查它有产出。也许你的某个组件也在沉默地空转。全剧终运维的剧永远在续订。本文为《两万个项目堆成山》系列第二集基于 Dependency-Track 4.11.4 的真实运维经历撰写。文中所有命令与脚本均已在生产环境验证敏感信息已做脱敏处理。环境不同坑的形状可能不同请酌情参考。
返回列表