2025年8月12日
npm重大事件:如何保护项目免受供应链攻击
2025 年 7 月,npm 生态遭遇了其历史上最大规模的供应链攻击之一。攻击者获取了热门包维护者的账号访问权限,并发布了恶意版本,数以百万计的开发者在不知情的情况下安装了这些版本。
发生了什么
受影响的包:
eslint-config-prettier— 每周 3000 万+ 下载。恶意版本:8.10.1、9.1.1、10.1.6、10.1.7eslint-plugin-prettiersynckit@pkgr/corenapi-postinstallis— 每周 280 万下载。恶意版本:3.3.1–5.0.0
攻击过程:
- 通过仿冒域名
npnjs.com实施网络钓鱼 → 维护者输入了凭据。 - 攻击者获得访问权限并直接向 npm 发布恶意构建。
- 恶意代码伪装为
postinstall脚本,下载 DLL 或开启 WebSocket 后门。 - 这些发布绕过了 GitHub 仓库——常规的提交监控不起作用。
总影响 — 每周超过 1.8 亿次下载。
来源:
如何防御类似攻击
1. 固定精确版本
在 package.json 中:
"eslint-config-prettier": "10.1.0"
不要这样:
"eslint-config-prettier": "^10.1.0"
让 npm 在今后的安装中默认保存精确版本的命令:
npm config set save-exact true
在仓库的 .npmrc 中还可以强制:
save-exact=true
如何快速为整个项目固定版本
如果你的 package.json 已经使用了 ^ 或 ~,可以快速移除并改为精确版本。
npm:
npx npm-check-updates -f "/.*/" --removeRange --upgrade
npm-check-updates是一个管理依赖版本的工具。--removeRange会从所有条目中移除^和~。
npm-check-updates 并不读取 package-lock.json。它只操作 package.json,将依赖版本替换为 npm 上的最新版本(可按你的过滤条件和限制)。如果你在仓库中提交了 package-lock.json,更安全的做法是直接根据 lockfile 固定版本。这里有一个可用的 Node.js 脚本,可以从 package-lock.json 读取精确版本并写入 package.json(且不含 ^ 与 ~)。
2. 使用 lockfile
将 package-lock.json 提交到仓库。这样可以固定所有依赖(包括传递依赖)。
3. 启用依赖审计
npm audit
4. 尽量减少 postinstall 脚本
除非绝对必要,避免使用在安装阶段执行代码的依赖。
5. 为 npm 账号开启双重验证(2FA)
即便密码泄露,也能显著降低被接管风险。
6. 核对邮件与域名
不要直接点击“官方”邮件中的链接,先核对地址。npmjs.com 与 npnjs.com 只差一个字母。
结语
供应链攻击愈发频繁,即便是历史悠久的热门包也可能遭到入侵。减少自动更新、管控依赖并保持警惕,是保护项目的关键步骤。


