供应链攻击已成为 JavaScript 生态的头号威胁。2025 年的 Shai-Hulud 和 SHA1-Hulud 事件表明,攻击者正系统性地利用 postinstall 等生命周期脚本作为执行入口 —— 一旦安装被污染的依赖包,恶意代码便可在开发者本地机器和 CI/CD 环境中运行,窃取 npm、GitHub 及云服务商凭证,甚至将受害者转化为攻击者控制的 GitHub Actions 自托管运行器。
面对这种威胁,单个包管理器的安全配置已不足够。开发团队往往同时使用 npm、pnpm、Yarn、Bun 乃至 Python 的 uv,每种工具的配置文件格式、参数名称和生效范围各不相同,导致安全策略难以统一执行和审计。DepsGuard 正是为解决这一碎片化问题而生:它通过单一静态二进制文件,自动扫描并加固多生态系统的包管理器配置,建立可复现的安全基线。
DepsGuard 的核心价值
DepsGuard 采用 Rust 编写,零第三方依赖,以单一静态二进制形式分发。它不执行任何包安装操作,仅读取和修改配置文件,且在每次变更前自动创建备份。这种设计哲学体现了 "最小权限原则"—— 工具本身不接触网络,不执行外部代码,仅作为配置的审计者和修复者存在。
该工具支持五种主流包管理器(npm、pnpm、Yarn、Bun、uv)以及 Renovate 和 Dependabot 的自动化配置,覆盖从个人开发环境到团队协作的完整场景。其交互式 TUI 界面允许开发者逐项审查建议的加固措施,预览 diff 后再决定是否应用,避免自动化工具常见的 "黑盒操作" 焦虑。
五大加固策略与可落地参数
DepsGuard 围绕供应链攻击的关键攻击面,提炼出五项核心加固策略。以下逐一解析其原理、配置参数及版本要求。
1. 发布冷却期(Release Cooldown)
原理:恶意包往往在被发现后数小时内就会被下架,但在此之前可能已经感染大量用户。通过强制延迟安装新发布的版本(通常设为 7 天),可以让社区有时间识别和标记恶意包。
配置参数:
- npm(≥11.10):
min-release-age=7(单位:天) - pnpm(≥10.16):
minimum-release-age=10080(单位:分钟,即 7 天) - Yarn(≥4.10):
npmMinimalAgeGate: 7d - Bun:
install.minimumReleaseAge = 604800(单位:秒) - uv(≥0.9.17):
exclude-newer = "7 days" - Renovate:
minimumReleaseAge: "7 days" - Dependabot:
cooldown.default-days: 7
实施要点:冷却期应作用于全局用户配置(如 ~/.npmrc),确保所有项目默认受保护。对于 Monorepo,可在 pnpm-workspace.yaml 中覆盖特定值。
2. 安装脚本阻断(Ignore Scripts)
原理:preinstall、postinstall 等生命周期脚本是供应链攻击的主要执行载体。Shai-Hulud 攻击正是通过篡改 ngx-bootstrap 等流行包的 postinstall 钩子植入恶意代码。
配置参数:
- npm/pnpm:
ignore-scripts=true - pnpm(额外加固):
strict-dep-builds=true(要求显式审查构建脚本)
权衡与例外:某些合法包(如 bcrypt、playwright)确实需要编译原生模块。建议采用白名单机制而非全局放行。pnpm 的 allowBuilds 和 Bun 的 trustedDependencies 都支持按包名精确授权。
3. 传递依赖阻断(Block Exotic Subdeps)
原理:攻击者常通过传递依赖(transitive dependencies)植入恶意代码,因为开发者往往只审查直接依赖。阻断 "异域"(exotic)来源的传递依赖可缩小攻击面。
配置参数:
- pnpm(≥10.26):
block-exotic-subdeps=true
适用场景:当项目依赖树中存在来自非标准 registry 或 Git 仓库的传递依赖时,此设置会触发警告或阻断。
4. 来源验证策略(Trust Policy)
原理:NPM 的 provenance 功能允许验证包是否由预期的 CI/CD 流水线构建。攻击者可能尝试 "降级" 来源验证(如从有 provenance 的版本切换到无 provenance 的版本),此策略可阻断此类行为。
配置参数:
- pnpm(≥10.21):
trust-policy=no-downgrade
补充措施:对于自行发布的包,应启用 npm publish --provenance 生成构建来源证明,并配置 OIDC 可信发布(Trusted Publishing)消除长期有效令牌的风险。
5. 确定性安装(Deterministic Installs)
原理:锁定文件(lockfile)是供应链的 "合同"。npm install 可能因版本解析策略而修改锁定文件,引入未预期的依赖版本。CI/CD 环境应强制使用确定性安装命令。
配置参数:
- npm:使用
npm ci而非npm install - pnpm:
pnpm install --frozen-lockfile - Yarn:
yarn install --frozen-lockfile - Bun:
bun install --frozen-lockfile
CI 集成:在 CI 流水线中,应将锁定文件变更视为需要人工审查的安全事件。可配合 lockfile-lint 等工具验证锁定文件中的 URL 和完整性哈希。
配置文件位置速查
不同包管理器的配置文件位置因操作系统而异,DepsGuard 会自动检测以下路径:
| 包管理器 | Linux/macOS | Windows |
|---|---|---|
| npm/pnpm | ~/.npmrc |
%USERPROFILE%\.npmrc |
| pnpm 全局 | ~/.config/pnpm/rc 或 config.yaml |
%LOCALAPPDATA%\pnpm\config\rc |
| Yarn | ~/.yarnrc.yml |
%USERPROFILE%\.yarnrc.yml |
| Bun | ~/.bunfig.toml |
%USERPROFILE%\.bunfig.toml |
| uv | ~/.config/uv/uv.toml |
%APPDATA%\uv\uv.toml |
对于项目级配置,DepsGuard 会递归扫描当前目录下的 .npmrc、.yarnrc.yml、pnpm-workspace.yaml、.github/dependabot.yml 等文件。
紧急安全修复的绕过机制
冷却期策略在常态下有效,但在紧急安全修复场景下需要临时绕过。DepsGuard 文档提供了各包管理器的精确绕过方法,核心原则是 "最小范围例外":
- npm:
npm install <pkg>@<ver> --min-release-age=0 - pnpm:在
pnpm-workspace.yaml中添加minimumReleaseAgeExclude条目,安装后移除 - Yarn:通过
YARN_NPM_MINIMAL_AGE_GATE=0s环境变量临时覆盖 - Bun:
bun add <pkg>@<ver> --minimum-release-age 0 - uv:在
uv.toml中设置exclude-newer-package."<pkg>" = false
操作流程:验证 CVE 影响范围 → 检查是否存在已知安全的旧版本 → 必要时添加临时例外 → 安装修复版本 → 立即移除例外 → 重新扫描验证。
实施建议
-
渐进式推广:先在个人开发环境运行
depsguard scan生成报告,识别当前配置缺口,再逐步应用修复。 -
团队标准化:将加固后的配置文件纳入团队仓库模板,新成员 onboarding 时自动继承安全基线。
-
CI 门禁:在 CI 中运行
depsguard scan作为检查步骤,阻止不合规配置进入主分支。 -
备份与回滚:DepsGuard 自动在
~/.depsguard/backups/创建备份,但建议团队额外将加固前的配置纳入版本控制,便于审计和回滚。 -
结合其他工具:DepsGuard 专注于配置加固,应与依赖漏洞扫描(如 Snyk、npm audit)、锁定文件校验(lockfile-lint)和开发环境隔离(Dev Containers)形成纵深防御。
资料来源
- DepsGuard GitHub 仓库: https://github.com/arnica/DepsGuard
- Snyk - NPM Security Best Practices: How to Protect Your Packages After the 2025 Shai Hulud Attack
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。