企业在依赖开源组件时面临的核心风险在于包的可信度无法仅通过版本号判断。2025 年 9 月 LiteLLM 项目遭遇的供应链攻击堪称典型案例:攻击者通过维护者账号入侵,在litellm-dashboard的package-lock.json中引入了伪装成 Node.js 内置模块的恶意fs@0.0.1-security包,该包被 OSSF 恶意包数据库标记为 CVE 编号 MAL-2025-21003,CVSS 评分高达 9.8。事件本质是依赖混淆攻击 —— 由于fs本属 Node.js 核心模块,任何外部安装行为均属异常,却因供应链管理疏漏而绕过检测。此类攻击的隐蔽性决定了企业必须将包完整性校验下沉至 CI/CD 流水线,在安装前完成阻断而非事后响应。
构建自动化防御体系需围绕三个核心能力展开:发布阶段生成可验证的密码学证据、传输阶段确保包未被篡改、消费阶段在安装前完成证据校验。对于 npm 生态,主流方案采用 Sigstore 的 Cosign 工具链实现工件签名与验证。开发者应在发布流程中嵌入签名步骤:以 GitHub Actions 为例,工作流需配置cosign sign命令对 tarball 生成签名,并将签名与.attestation 文件同步推送至 registry 或独立存储。验证阶段则使用cosign verify配合 OIDC 身份校验,确保仅接受来自受信任 CI 流水线签名的包。关键参数包括:验证时指定--certificate-identity为企业域名或组织 OIDC issuer,排除未知签发方的所有包;设置--certificate-oidc-issuer为https://token.actions.githubusercontent.com以绑定 GitHub Actions 工作流身份。对于 PyPI 生态,流程类似但需处理 wheel 与 sdist 两种发布格式,建议在.pypirc中配置 Trusted Publishing 消除 API Token 持久化风险,并利用 PyPI 现已对前 5000 名热门包强制构建证明的政策红利。
具体到 CI/CD 流水线集成,推荐采用双阶段门禁设计。第一阶段为构建时门禁:在依赖安装完成后、单元测试执行前,插入校验脚本扫描package-lock.json与poetry.lock中的所有外部依赖。校验维度包括:检测 Node.js 核心模块名称(如fs、path、crypto)是否被列为外部依赖、比对当前 lockfile 与上一次提交的历史哈希以检测异常新增依赖、调用 OSSF Malicious Packages REST API 对所有第三方包版本进行恶意包数据库查询。触发阈值建议设为:核心模块名称匹配直接失败、外部依赖哈希变化需人工审批、OSSF 数据库命中则自动阻断并触发安全告警。第二阶段为部署前门禁:在制品进入 staging 或生产环境前,验证所有依赖包的签名与证明文件完整性,确保部署产物与 CI 阶段检验的包版本一致。
监控与响应机制同样关键。企业应部署依赖变更的持续监控能力:每日定时比对线上环境的 lockfile 与基线版本,记录新增依赖、新版本引入、依赖传递深度异常增长等信号。建议将依赖传递层级阈值设为不超过 5 层,超过后触发审查流程;单次依赖解析耗时超过 30 秒可能暗示依赖图异常。在检测到供应链事件时,快速回滚能力依赖于制品版本的精确锁定与部署流水线的可重复性。建议在 CI 中为每次构建生成包含完整依赖树哈希的 SBOM(Software Bill of Materials),并将该 SBOM 与构建产物一同存储至少一年,以便事后溯源与影响面评估。
技术落地上需注意几个常见误区。其一,仅依赖npm audit或pip-audit不足以防御供应链攻击,这些工具聚焦已知漏洞而非恶意包;其二,lockfile 的版本锁定是必要条件但非充分条件 ——LiteLLM 事件中 lockfile 本身已被污染,必须配合签名验证;其三,内部镜像源不能消除上游风险,仍需对所有入站包进行校验。企业在实施时可优先从阻断 Node.js 核心模块的外部依赖开始,逐步叠加签名验证与 OSSF 数据库查询,形成多层防御体系。
资料来源:LiteLLM 安全事件详情见 GitHub Issue #14446;npm 包完整性校验最佳实践参考 Cosign 官方文档与 GitLab CI/CD 集成指南。