问题与范围
平台接入数百万仓库。每个仓库可提交锁文件、镜像清单或 SBOM;漏洞源会新增、修订、撤回记录。请设计从清单摄取、版本匹配、告警生成到通知和修复验证的系统。默认支持 npm、PyPI、Maven 三类生态;代码扫描、自动合并补丁和漏洞本身的人工判定不在范围内。
采用以下面试假设:每天 1000 万次清单更新,平均每份含 150 个依赖;每天新增或修订 2 万条漏洞记录;同一漏洞在多个仓库出现。首次告警希望在清单提交后 5 分钟内可见,漏洞撤回后 15 分钟内停止新通知,历史告警保留 2 年。数字用于容量推导,不代表行业基准。
面试官在考察什么
核心是把“依赖版本命中漏洞”与“告警生命周期”分开。版本范围、生态规范化、直接与传递依赖、修订后的漏洞记录和撤回状态都可能改变结果;不能把一次扫描结果当永久事实。优秀答案还会说明去重键、可重放摄取、通知幂等、权限隔离和修复后重新验证。
回答前要澄清的问题
- 清单是锁定版本还是允许范围?漏洞匹配按解析后的实际版本,还是按声明范围预警?
- 是否需要识别传递依赖、开发依赖、容器镜像层和私有包?
- 漏洞源是否允许撤回、别名和严重性修订?历史告警是否保留原快照?
- 一个仓库的多个分支如何归并?分支删除后告警是否继续存在?
- 通知渠道、频率和组织级静音规则如何定义?
30 秒回答框架
“我会把清单规范化成不可变快照,按生态解析依赖图,再用版本区间索引匹配漏洞记录。匹配结果写成幂等的告警投影,键包含仓库、依赖、漏洞和受影响版本快照;漏洞修订会触发增量重算。摄取、漏洞更新和通知都通过持久队列可重放,通知按组织策略聚合并带幂等键。告警保留证据快照,修复验证重新扫描当前提交,同时用权限检查、对账和延迟指标保证可解释性。”
分步深入设计
控制面保存组织、仓库、分支和通知策略。摄取 API 接收带提交哈希的清单,先写对象存储和元数据,再发布 manifest_received 事件。相同仓库、分支、提交和清单摘要重复提交时返回已有快照,不重复建立扫描任务。大型 SBOM 使用分片上传和校验,租户配额防止恶意超大清单拖垮解析器。
解析器按生态规则规范化名称与版本,并展开锁定的传递依赖。每个快照产出标准化组件坐标、来源位置和开发/生产范围。解析失败要保留原始文件、错误位置和可重试状态;不能把“无法解析”当成“没有漏洞”。解析服务无状态扩展,结果写入按仓库和组件哈希分区的持久存储。
漏洞摄取器从 OSV 等源拉取或接收增量,验证 schema、来源签名和版本号。漏洞记录包含受影响生态、包名、版本区间、别名、严重性、修复版本、发布时间、更新时间和撤回标记。区间匹配器使用生态感知比较而非字符串排序,并为高频组件建立倒排索引。漏洞修订只重算受影响组件,记录匹配规则版本,避免全库扫描。
告警表至少包含 alertid、组织、仓库、分支、组件坐标、漏洞 ID、证据快照、状态、首次发现、最近确认、修复提交和规则版本。(repository, branch, component, vulnerabilityid, vulnerable_version) 唯一约束防止重复告警;同一漏洞的别名集合要先归一化。状态可从 OPEN 到 FIXED、DISMISSED、REOPENED,每次迁移写审计事件。漏洞撤回不会抹掉历史,而是停止新通知并显示撤回依据。
通知不是扫描事务的一部分。告警事件进入按组织分区的队列,由聚合器按策略合并相似告警、设置冷却窗口并生成稳定的通知键。邮件、代码托管评论和聊天适配器各自限流、重试和记录投递结果;消费者用通知键幂等。组织管理员可按漏洞、组件或路径静音,但静音规则必须有期限、操作者和审计原因,严重性升级可绕过过期静音。
修复验证接收新的提交或定期快照,重新解析依赖图并运行同一匹配规则。只有当前默认分支快照不再命中,或组织明确接受风险,告警才可关闭。修复版本信息只能作为建议,不能替代实际扫描。旧分支告警继续保留到分支删除或保留期结束,避免开发者误以为生产已修复。
可靠性依赖可重放事件和对账。对账任务比较已存清单、解析结果、匹配结果和告警投影的计数;比较漏洞源版本与本地版本;比较应发送通知与适配器回执。监控清单摄取到告警的 p95 延迟、解析失败率、漏洞更新积压、匹配吞吐、重复率、撤回传播延迟、通知重试和静音命中。故障注入覆盖队列重复、漏洞修订中途崩溃、索引落后、通知适配器超时和数据库恢复。
高质量示范回答
“我会先保存带提交哈希的原始清单,再用生态解析器生成规范化依赖图。OSV 这类漏洞源以可验证版本号持续更新;摄取器按漏洞版本增量更新倒排索引。匹配结果写成带证据快照和规则版本的幂等告警,唯一键防止同一仓库、组件和漏洞重复。漏洞撤回只关闭新通知,历史记录保留撤回原因。
通知事件通过持久队列与扫描事务解耦,按组织聚合并使用稳定键重试。静音有期限、原因和审计记录,严重性升级可重新唤醒。每次新提交都重新解析当前依赖图,只有实际不再命中才标记修复。对账任务检查清单、漏洞源、告警和通知四个边界,指标覆盖五分钟可见性、十五分钟撤回传播、积压、重复和适配器失败。这样系统既能扩展每日千万清单,也能解释某条告警为何出现、何时撤回以及为何重新打开。”
常见错误
- 只比较包名 → 不同生态和版本范围会产生大量误报 → 使用生态坐标与区间比较。
- 把解析失败当成安全 → 锁文件损坏会静默漏报 → 保留失败状态和原始证据并重试。
- 每次扫描都新建告警 → 同一问题通知轰炸 → 使用组件、漏洞和版本证据组成幂等键。
- 覆盖更新漏洞记录 → 无法解释历史严重性和撤回 → 保存版本化记录与证据快照。
- 通知放在扫描事务内 → 邮件超时拖慢告警生成 → 用持久事件和适配器队列解耦。
- 关闭告警只看建议修复版本 → 实际提交可能仍锁定旧版本 → 对当前提交重新解析和匹配。
- 静音永久有效 → 风险长期无人负责 → 要求期限、原因和到期提醒。
- 漏洞别名分别告警 → 一个问题显示多条重复项 → 先归一化别名集合。
追问与回答
追问一:如何处理漏洞范围修订?
漏洞版本变更递增源版本,生成受影响组件集合,只重算命中的仓库快照。告警保存规则版本和匹配证据;结果变化时写状态迁移。若索引更新落后,指标和对账任务应明确显示暂时不完整,而不是继续显示“安全”。
追问二:为什么保留原始清单?
解析器和漏洞规则会升级。原始文件允许在新规则下重放,审计时也能证明某次告警基于哪个提交。对象存储配合校验和生命周期策略,在线数据库只保留索引与当前投影。
追问三:如何减少通知疲劳?
按组织策略聚合相同漏洞和组件,提供冷却窗口、摘要和可配置渠道。静音规则限定范围、期限和原因;严重性上调、撤回或修复状态变化可立即打破冷却。每条通知仍有稳定键,重试不会重复发送。
追问四:传递依赖如何避免误判?
以锁定图为准记录父依赖路径、直接或传递类型和环境范围。修复建议优先给出能改变实际解析版本的最小升级;若构建工具解析不确定,显示“无法确认”并要求补交锁文件,而不是猜测。
追问五:多分支如何建模?
分支是清单快照的维度,告警键包含分支或引用。默认分支用于组织风险摘要;分支删除产生终止事件,不删除审计记录。相同提交哈希可复用解析结果,但每个分支仍有自己的告警状态。
追问六:漏洞源不可用时怎么办?
继续使用最后一次经过校验的源版本并明确标记新鲜度,暂停“无漏洞”结论。抓取器指数退避并从可用镜像恢复;恢复后按源版本差量补算。严重漏洞源长时间不更新应触发运维告警。