bodadotsh/npm-security-best-practices
GitHub: bodadotsh/npm-security-best-practices
Stars: 762 | Forks: 19

# NPM 安全最佳实践
## 目录
- [遭受攻击了?](#got-compromised)
- [立即采取的行动](#immediate-actions-to-take)
- [面向开发者](#for-developers)
- [0. 了解你的包](#0-know-thy-package)
- [1. 锁定依赖版本](#1-pin-dependency-versions)
- [2. 包含 lockfiles](#2-include-lockfiles)
- [3. 禁用生命周期脚本](#3-disable-lifecycle-scripts)
- [4. 安装前预防措施](#4-preinstall-preventions)
- [5. 运行时保护](#5-runtime-protections)
- [6. 减少外部依赖](#6-reduce-external-dependencies)
- [7. 隔离开发环境](#7-isolated-development)
- [面向维护者](#for-maintainers)
- [8. 启用 2FA](#8-enable-2fa)
- [9. 创建受限访问的 Tokens](#9-create-tokens-with-limited-access)
- [10. 生成来源声明](#10-generate-provenance-statements)
- [11. 审查已发布文件](#11-review-published-files)
- [其他事项](#miscellaneous)
- [12. NPM 组织](#12-npm-organization)
- [13. 替代 Registry](#13-alternative-registry)
- [14. 审计、监控和安全工具](#14-audit-monitor-and-security-tools)
- [15. 支持 OSS](#15-support-oss)
## 遭受攻击了?
### 立即采取的行动
根据你的需求选择以下最佳实践,以加强你的系统防御下一次攻击的能力。
## 面向开发者
### 0. 了解你的包
### 1. 锁定依赖版本
以下是如何在各种包管理器中锁定确切版本:
```
npm install --save-exact react
pnpm add --save-exact react
yarn add --save-exact react
bun add --exact react
deno add npm:react@19.1.1
```
我们也可以在配置文件(例如 [`.npmrc`](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc))中更新此设置,使用 [`save-exact`](https://docs.npmjs.com/cli/v11/using-npm/config#save-exact) 或 [`save-prefix`](https://docs.npmjs.com/cli/v11/using-npm/config#save-prefix) 键值对:
```
npm config set save-exact=true
pnpm config set save-exact true
yarn config set defaultSemverRangePrefix ""
```
对于 `bun`,配置文件是 `bunfig.toml`,相应的配置是:
```
[install]
exact = true
```
#### 覆盖传递依赖
在 `package.json` 中,如果我们有以下 `overrides` 字段:
```
{
"dependencies": {
"library-a": "^3.0.0"
},
"overrides": {
"lodash": "4.17.21"
}
}
```
- 让我们假设 `library-a` 的 `package.json` 有一个依赖项 `"lodash": "^4.17.0"`
- 如果没有 `overrides` 部分,`npm` 可能会安装 `lodash@4.17.22`(或任何最新的 `4.x.x` 版本)作为 `library-a` 的传递依赖
- 但是,通过添加 `"overrides": { "lodash": "4.17.21" }`,我们告诉 `npm`,无论 `lodash` 出现在依赖树的哪个位置,都必须精确解析为版本 `4.17.21`
对于 `pnpm`,我们也可以在 `pnpm-workspace.yaml` 文件中定义 `overrides` 字段:
对于 `yarn`,`resolutions` 字段在 `overrides` 字段之前引入,它也提供了类似的功能:
```
{
"resolutions": {
"lodash": "4.17.21"
}
}
```
```
# yarn 也提供了一个 CLI 来设置 resolution:https://yarnpkg.com/cli/set/resolution
yarn set resolution
```
对于 `bun`,它支持 `overrides` 字段或 `resolutions` 字段:
对于 `deno` 和 `deno.json`,请参阅 :
```
{
"links": [
"../path/to/local_npm_package"
]
}
```
### 2. 包含 Lockfiles
```
npm ci
bun install --frozen-lockfile
yarn install --frozen-lockfile
pnpm install --frozen-lockfile
deno install --frozen
```
对于 `deno`,我们也可以在 `deno.json` 文件中设置以下内容:
```
{
"lock": {
"frozen": true
}
}
```
### 3. 禁用生命周期脚本
```
npm config set ignore-scripts true --global
yarn config set enableScripts false
```
对于 `bun`、`deno` 和 `pnpm`,它们默认是禁用的。
### 4. 安装前预防措施
#### 安装前扫描器
```
npm i -g sfw
# 适用于 `npm`、`yarn`、`pnpm`
sfw npm install
# 示例:在 zsh 中将 `npm` 别名为 `sfw npm`
# echo "alias npm='sfw npm'" >> ~/.zshrc
```
Aikido Safe Chain 封装了 npm cli、`npx`、`yarn`、`pnpm`、`pnpx`、`bun`、`bunx` 和 `pip`,以便在安装新包之前提供额外的检查
```
npm install -g @aikidosec/safe-chain
```
```
npq install express
NPQ_PKG_MGR=pnpm npx npq install fastify
```
使用 Bun,我们可以使用其 [安全扫描器 API](https://bun.com/docs/pm/security-scanner-api)
```
bun add -d @socketsecurity/bun-security-scanner
```
从 Bun v1.3+ 开始,你可以[将 Socket 与 Bun 集成](https://socket.dev/blog/socket-integrates-with-bun-1-3-security-scanner-api)
```
# 在 bunfig.toml 中
[install.security]
scanner = "@socketsecurity/bun-security-scanner"
```
#### 设置最小发布龄期
```
npm install --before=2025-10-22
# 仅安装至少发布 1 天的 package
npm install --before="$(date -v -1d)" # for Mac or BSD users
npm install --before="$(date -d '1 days ago' +%Y-%m-%dT%H:%M:%S%z)" # for Linux users
# 其他相关 flags:minimumReleaseAgeExclude
pnpm config set minimumReleaseAge
# 其他相关 flags:npmPreapprovedPackages
yarn config set npmMinimalAgeGate
```
对于 `npm`,有一项[提案](https://github.com/npm/cli/issues/8570)要添加 `minimumReleaseAge` 选项和 `minimumReleaseAgeExclude` 选项。
对于 `bun`,自 [`v1.3`](https://bun.com/docs/cli/install#minimum-release-age) 起支持 `minimumReleaseAge` 和 `minimumReleaseAgeExcludes` 选项。
```
[install]
minimumReleaseAge = 604800 # 7 days in seconds
```
对于 `deno`,他们很快也会推出类似的功能:
提供类似功能的其他工具示例:
- `npm-check-updates` () 有 `--cooldown/-c` 标志,例如:`npx npm-check-updates -i --format group -c 7`
- Renovate CLI () 有一个 [`minimumReleaseAge`](https://docs.renovatebot.com/configuration-options/#minimumreleaseage) 配置选项。
- Step Security () 有一个 [NPM Package Cooldown Check](https://www.stepsecurity.io/blog/introducing-the-npm-package-cooldown-check) 功能。
### 5. 运行时保护
大多数技术都集中在 _安装_ 和 _构建_ 阶段,我们可以在 JavaScript 应用程序的 _运行时_ 阶段添加额外的安全层。
#### 权限模型
阅读关于 Node.js 权限模型的信息:
```
# 默认授予完全访问权限
node index.js
# 限制对所有可用权限的访问
node --permission index.js
# 启用特定权限
node --permission --allow-fs-read=* --allow-fs-write=* index.js
# 使用 `npx` 的权限模型
npx --node-options="--permission"
```
Deno 默认禁用权限。请参阅
```
# 默认情况下限制访问
deno run script.ts
# 启用特定权限
deno run --allow-read script.ts
```
对于 Bun,权限模型目前在[这里](https://github.com/oven-sh/bun/discussions/725)和[这里](https://github.com/oven-sh/bun/issues/6617)进行讨论。
#### 强化 JavaScript
像 MetaMask 和 Moddable 这样的公司使用 和 来启用运行时保护,例如防止修改 JavaScript 的原始对象(Object、String、Number、Array 等),并限制对平台 API(window、document、XHR 等)的每个包访问。这些机制也被提议为 TC39 提案,如
### 6. 减少外部依赖
在 `nodejs`、`bun`、`deno` 和 Web API 之间,开发者可以使用它们的许多现代功能,而不是依赖第三方库。原生模块可能无法提供相同级别的功能,但应尽可能考虑使用它们。以下是几个例子:
| NPM 库 | 内置模块 |
| -------------------------------- | ------------------------------------------------------------------- |
| `axios`, `node-fetch`, `got` 等 | 原生 `fetch` API |
| `jest`, `mocha`, `ava` 等 | `node:test`, `node:assert`, `bun test` 和 `deno test` |
| `nodemon`, `chokidar` 等 | `node --watch`, `bun --watch` 和 `deno --watch` |
| `dotenv`, `dotenv-expand` 等 | `node --env-file`, `bun --env-file` 和 `deno --env-file` |
| `typescript`, `ts-node` 等 | `node --experimental-strip-types`[^10], `deno` 和 `bun` 原生支持 |
| `esbuild`, `rollup` 等 | `bun build` 和 `deno bundle` |
| `prettier`, `eslint` 等 | `deno lint` 和 `deno fmt` |
以下是一些你可能会觉得有用的资源:
-
-
-
-
-
- 可视化库依赖关系:
- 在线分析依赖元数据:,或本地:`pnpm dlx node-modules-inspector`
- Knip(移除未使用的依赖项):
- 使用 [`npkill`](https://github.com/voidcosmos/npkill) 清除不需要的 `node_modules`:`cd ~ && npx npkill`
### 7. 隔离开发环境
在隔离环境中开发代码是防止供应链攻击的一种流行且有效的方法。一些知名的本地虚拟机 (VM) 解决方案包括:[VirtualBox](https://www.virtualbox.org/)、[VMware Fusion](https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion)、[Parallels Desktop](https://www.parallels.com/) 和 [OrbStack](https://orbstack.dev/)。
云沙盒也提供了更简单的设置路径,并且可以直接在浏览器中使用,流行的产品包括:[CodeSandbox](https://codesandbox.io)、[Ona (前身为 Gitpod)](https://ona.com/)、[GitHub Codespaces](https://github.com/features/codespaces) 等等。
基于容器的开发也越来越受欢迎,特别是随着专注于丰富容器中开发特定内容和设置的 [Development Containers](https://containers.dev/) 规范的推出。
如果你有任何好的技巧或反馈,[请在此处加入讨论](https://github.com/bodadotsh/npm-security-best-practices/issues/3)!
## 面向维护者
### 8. 启用 2FA
```
# 确保 auth 和 writes 启用了 2FA(这是默认设置)
npm profile enable-2fa auth-and-writes
```
| 自动化级别 | 包发布访问权限 |
| ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
| 手动 | 将每个包的访问权限设置为 `Require 2FA` 和 `Disable Tokens` |
| 自动 | 将每个包的访问权限设置为 `Require two-factor authentication` 或 `Single factor automation tokens` 或 `Single factor granular access tokens` |
### 9. 创建受限访问的 Tokens
通过网站创建细粒度访问令牌: 或 `npm` cli:
`npm login` cli 命令启用两小时的会话令牌,而不是长期有效的令牌。在这些会话期间,发布操作会强制执行 2FA,从而增加了一层额外的安全性。
以下是创建令牌时的一些最佳实践:
- 描述性的令牌名称
- 将令牌限制为特定的包、范围和组织
- 设置令牌过期日期(例如,每年)
- 根据 IP 地址范围(CIDR 表示法)限制令牌访问
- 在只读或读写访问之间进行选择
- 不要将同一个令牌用于多种目的
### 10. 生成来源声明
要建立来源,请使用支持的 CI/CD 提供商(例如 GitHub Actions)并使用正确的标志进行发布:
```
npm publish --provenance
```
要在不调用 `npm publish` 命令的情况下进行发布,我们可以执行以下操作之一:
- 在 CI/CD 环境中将 `NPM_CONFIG_PROVENANCE` 设置为 `true`
- 将 `provenance=true` 添加到 `.npmrc` 文件
- 将 `publishConfig` 块添加到 `package.json`
```
"publishConfig": {
"provenance": true
}
```
#### 可信发布
当使用 OpenID Connect (OIDC) 身份验证时,可以在 _不需要_ npm 令牌的情况下发布包,并获得 _自动_ 来源证明。这被称为 **可信发布**,请在此处阅读 GitHub 公告:
有关如何配置可信发布的说明,请参阅 。
相关工具:
- (用于为 monorepo 包设置可信发布者的 CLI)
- (用于在 npmjs.com 上填写可信发布者表单的用户脚本)
### 11. 审查已发布文件
`package.json` 中的 `files` 字段用于指定应包含在已发布包中的文件。某些文件总是包含在内,有关更多详细信息,请参阅:
```
{
"name": "my-package",
"version": "1.0.0",
"main": "dist/index.js",
"files": ["dist", "LICENSE", "README.md"]
}
```
运行 `npm pack --dry-run` `npm publish --dry-run` 来查看当我们运行 pack 或 publish 命令时会发生什么。
```
> npm pack --dry-run
npm notice Tarball Contents
npm notice 1.1kB LICENSE
npm notice 1.9kB README.md
npm notice 108B index.js
npm notice 700B package.json
npm notice Tarball Details
```
在 `deno.json` 中,使用 `publish.include` 和 `publish.exclude` 字段指定应包含或排除的文件:
```
{
"publish": {
"include": ["dist/", "README.md", "deno.json"],
"exclude": ["**/*.test.*"]
}
}
```
## 其他事项
### 12. NPM 组织
在组织层面,最佳实践是:
- 在组织级别启用 `Require 2FA`
- 最小化 `npm` 组织成员的数量
- 如果同一组织中有多个包团队,请将所有包的 `developers` 团队权限设置为 `READ`
- 创建单独的团队来管理每个包的权限
### 13. 替代 Registry
JSR 是一个现代的 JavaScript/TypeScript 包注册中心,与 npm 向后兼容。
```
deno add jsr:
pnpm add jsr: # pnpm 10.9+
yarn add jsr: # yarn 4.9+
# npm、bun 以及旧版本的 yarn 或 pnpm
npx jsr add # replace npx with yarn dlx, pnpm dlx, or bunx
```
#### 私有 Registry
以下是一些你可能会觉得有用的私有注册中心:
- GitHub Packages
- Verdaccio
- 查看 Verdaccio 最佳实践:
- Vlt
- [vlt 的无服务器 Registry](https://docs.vlt.sh/registry) (VSR) 可以在几分钟内部署到 Cloudflare Workers。
- JFrog Artifactory
- Sonatype:
### 14. 审计、监控和安全工具
#### 审计
```
npm audit # audit dependencies
npm audit fix # automatically install any compatible updates
npm audit signatures # verify the signatures of the dependencies
pnpm audit
pnpm audit --fix
bun audit
deno audit
deno audit --socket
yarn npm audit
yarn npm audit --recursive # audit transitive dependencies
```
#### GitHub
GitHub 提供了几种服务,可以帮助防御 `npm` 恶意软件,包括:
- [Dependabot](https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide):此工具会自动扫描你项目的依赖项,包括 `npm` 包,以查找已知的漏洞。
- [软件物料清单](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exporting-a-software-bill-of-materials-for-your-repository):GitHub 允许你直接从其依赖图中导出存储库的 SBOM。SBOM 提供了项目所有依赖项的综合列表,包括传递依赖项(你依赖项的依赖项)。
- [代码扫描](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning):代码扫描还可以帮助识别潜在的漏洞或可疑模式,这些漏洞或模式可能是由于集成受损的 `npm` 包而引起的。
#### OpenSSF Scorecard
免费且开源的自动化工具,用于评估与软件安全相关的许多重要启发式方法(“检查”),并为每项检查分配 0-10 的分数。本存储库中提到的几个风险作为检查的一部分包括:锁定依赖项、令牌权限、打包、签名发布等。
运行检查:
1. 使用 [GitHub Action](https://github.com/marketplace/actions/ossf-scorecard-action) 自动对你拥有的代码运行
2. 通过 [命令行](https://github.com/ossf/scorecard#scorecard-command-line-interface) 手动对你的(或其他人的)项目运行
#### Socket.dev
Socket.dev 是一个安全平台,保护代码免受易受攻击和恶意的依赖项的侵害。它提供了各种工具,例如用于扫描拉取请求的 [GitHub App](https://socket.dev/features/github)、[CLI 工具](https://socket.dev/features/cli)、[Web 扩展](https://socket.dev/features/web-extension)、[VSCode 扩展](https://docs.socket.dev/docs/socket-for-vs-code) 等。这是他们关于 [AI 驱动的大规模恶意软件搜寻,2025 年 1 月](https://youtu.be/cxJPiMwoIyY) 的演讲。还有 [安装前扫描器部分](https://github.com/bodadotsh/npm-security-best-practices/tree/main?tab=readme-ov-file#preinstall-scanners) 中的 Socket Firewall `sfw` 工具。
#### Snyk
Snyk 提供了一套工具来修复开源依赖项中的漏洞,包括用于在本地机器上运行漏洞扫描的 CLI、用于嵌入开发环境的 IDE 集成,以及用于以编程方式与 Snyk 集成的 API。例如,你可以[在使用前测试公共 npm 包](https://docs.snyk.io/developer-tools/snyk-cli/scan-and-maintain-projects-using-the-cli/test-public-npm-packages-before-use)或[为已知漏洞创建自动 PR](https://docs.snyk.io/scan-with-snyk/pull-requests/snyk-pull-or-merge-requests/create-automatic-prs-for-backlog-issues-and-known-vulnerabilities-backlog-prs)。
#### FOSSA
FOSSA 是一个合规性和安全平台,可帮助组织管理其软件供应链的复杂性。它通过提供对所有软件组件(从[包和容器到二进制文件](https://fossa.com/products/scan/))的可见性来实现这一点。通过生成全面的 SBOM(软件物料清单),公司降低了法律和 IP 风险,整合了其代码库中的漏洞管理,并[遵守监管报告要求](https://fossa.com/solutions/due-diligence/)。
### 15. 支持 OSS
在 JavaScript 生态系统中,OpenJS Foundation () 于 2019 年由 JS Foundation 和 Node.js Foundation 合并成立,旨在支持一些最重要的 JS 项目。下面列出了其他几个平台,你可以在这些平台上捐赠和支持你每天使用的 OSS:
- GitHub Sponsors
- Open Collective
- Thanks.dev
- Open Source Pledge
- 生态系统基金:
## Star History
[](https://www.star-history.com/#bodadotsh/npm-security-best-practices&type=date&legend=top-left)
## 目录
- [遭受攻击了?](#got-compromised)
- [立即采取的行动](#immediate-actions-to-take)
- [面向开发者](#for-developers)
- [0. 了解你的包](#0-know-thy-package)
- [1. 锁定依赖版本](#1-pin-dependency-versions)
- [2. 包含 lockfiles](#2-include-lockfiles)
- [3. 禁用生命周期脚本](#3-disable-lifecycle-scripts)
- [4. 安装前预防措施](#4-preinstall-preventions)
- [5. 运行时保护](#5-runtime-protections)
- [6. 减少外部依赖](#6-reduce-external-dependencies)
- [7. 隔离开发环境](#7-isolated-development)
- [面向维护者](#for-maintainers)
- [8. 启用 2FA](#8-enable-2fa)
- [9. 创建受限访问的 Tokens](#9-create-tokens-with-limited-access)
- [10. 生成来源声明](#10-generate-provenance-statements)
- [11. 审查已发布文件](#11-review-published-files)
- [其他事项](#miscellaneous)
- [12. NPM 组织](#12-npm-organization)
- [13. 替代 Registry](#13-alternative-registry)
- [14. 审计、监控和安全工具](#14-audit-monitor-and-security-tools)
- [15. 支持 OSS](#15-support-oss)
## 遭受攻击了?
### 立即采取的行动
根据你的需求选择以下最佳实践,以加强你的系统防御下一次攻击的能力。
## 面向开发者
### 0. 了解你的包
### 1. 锁定依赖版本
以下是如何在各种包管理器中锁定确切版本:
```
npm install --save-exact react
pnpm add --save-exact react
yarn add --save-exact react
bun add --exact react
deno add npm:react@19.1.1
```
我们也可以在配置文件(例如 [`.npmrc`](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc))中更新此设置,使用 [`save-exact`](https://docs.npmjs.com/cli/v11/using-npm/config#save-exact) 或 [`save-prefix`](https://docs.npmjs.com/cli/v11/using-npm/config#save-prefix) 键值对:
```
npm config set save-exact=true
pnpm config set save-exact true
yarn config set defaultSemverRangePrefix ""
```
对于 `bun`,配置文件是 `bunfig.toml`,相应的配置是:
```
[install]
exact = true
```
#### 覆盖传递依赖
在 `package.json` 中,如果我们有以下 `overrides` 字段:
```
{
"dependencies": {
"library-a": "^3.0.0"
},
"overrides": {
"lodash": "4.17.21"
}
}
```
- 让我们假设 `library-a` 的 `package.json` 有一个依赖项 `"lodash": "^4.17.0"`
- 如果没有 `overrides` 部分,`npm` 可能会安装 `lodash@4.17.22`(或任何最新的 `4.x.x` 版本)作为 `library-a` 的传递依赖
- 但是,通过添加 `"overrides": { "lodash": "4.17.21" }`,我们告诉 `npm`,无论 `lodash` 出现在依赖树的哪个位置,都必须精确解析为版本 `4.17.21`
对于 `pnpm`,我们也可以在 `pnpm-workspace.yaml` 文件中定义 `overrides` 字段:标签:2FA, Cilium, CMS安全, DevSecOps, GNU通用公共许可证, JavaScript, MITM代理, Node.js, NPM, Syscall 审计, 上游代理, 依赖管理, 包管理器, 双因素认证, 开发者安全, 恶意软件防护, 数据可视化, 文档安全, 暗色界面, 最佳实践, 漏洞缓解, 生态安全, 统一API, 网络安全, 软件供应链, 软件开发工具包, 锁定文件, 防御指南, 隐私保护