npm v12 重大变更:安装脚本和远程依赖的全新安全默认设置

默认禁用安装脚本

从 v12 开始,npm install 将不再自动执行依赖项中的 preinstallinstallpostinstall 脚本。此更改还包括对包含 binding.gyp 文件的包的隐式 node-gyp rebuild 操作,以及对 git、file 和 link 依赖的 prepare 脚本。

要管理这些脚本,用户现在必须显式允许受信任的包:

  • 识别: 运行 npm approve-scripts --allow-scripts-pending 来识别哪些包会被阻止。
  • 批准: 使用 npm approve-scripts 允许受信任的包,使用 npm deny-scripts 阻止其他包。
  • 持久化: 生成的白名单会存储在 package.json 中,应该提交到版本控制。

限制 Git 和远程依赖解析

为封堵潜在的代码执行路径,npm v12 限制了从外部来源解析依赖的方式:

Git 依赖

npm install 将不再解析 Git 依赖(直接或传递),除非使用 --allow-git 标志。这可以防止出现 Git 依赖的 .npmrc 覆盖 Git 可执行文件的情况,即使脚本被忽略,此类漏洞仍然存在。

远程 URL 依赖

从远程 URL(例如 HTTPS tarball)解析的依赖默认会被阻止,除非提供 --allow-remote 标志。请注意,--allow-file--allow-directory 标志在 v12 中仍保持当前默认行为。

准备工作与迁移路径

开发者可以通过升级到 npm 11.16.0 或更高版本来为 v12 迁移做好准备。在该版本中,npm 会对将在 v12 中被阻止的行为给出警告。推荐的工作流程是执行一次标准安装,检查警告,并使用 npm approve-scripts --allow-scripts-pendingpackage.json 中生成并提交所需的白名单。

社区视角与技术批评

此公告在开发者中引发了关于这些变更的时机和有效性的广泛讨论。

供应链安全

一些用户指出,这些变更解决了早已被发现的漏洞,其中一位用户提到了 10 年前报告的漏洞。普遍认为,转向显式 opt-in 模式是应对供应链攻击的必要步骤,尽管也有人认为这相当于迟到的采纳,类似的模式早已在 pnpm 等其他包管理器中实现。

有效性与局限性

批评者认为,将执行从安装阶段转移到运行时阶段并未消除风险,只是把风险转移了:

现在所有恶意软件都可以从安装脚本转移到模块本身,而它仍然不可避免地会被运行

可用性担忧

关于 CLI 的易用性也有批评,尤其是 npm approve-scripts --allow-scripts-pending 的命名,一些人觉得不直观,因为该命令仅显示列表而非执行批准操作。

Sources