npm v12 重大变更:安装脚本和远程依赖的全新安全默认设置
默认禁用安装脚本
从 v12 开始,npm install 将不再自动执行依赖项中的 preinstall、install 或 postinstall 脚本。此更改还包括对包含 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-pending 在 package.json 中生成并提交所需的白名单。
社区视角与技术批评
此公告在开发者中引发了关于这些变更的时机和有效性的广泛讨论。
供应链安全
一些用户指出,这些变更解决了早已被发现的漏洞,其中一位用户提到了 10 年前报告的漏洞。普遍认为,转向显式 opt-in 模式是应对供应链攻击的必要步骤,尽管也有人认为这相当于迟到的采纳,类似的模式早已在 pnpm 等其他包管理器中实现。
有效性与局限性
批评者认为,将执行从安装阶段转移到运行时阶段并未消除风险,只是把风险转移了:
现在所有恶意软件都可以从安装脚本转移到模块本身,而它仍然不可避免地会被运行
可用性担忧
关于 CLI 的易用性也有批评,尤其是 npm approve-scripts --allow-scripts-pending 的命名,一些人觉得不直观,因为该命令仅显示列表而非执行批准操作。