NPM 包管理器安全最佳实践全指南:从开发到发布的全方位防护

100 阅读3分钟

npm 使用注意事项

禁用 post-install

npm config set ignore-scripts true

安装指定日期之前的包

npm install express --before=2025-01-01

使用 npq 安装包

npm install -g npq
alias npm='npq-hero'
echo "alias npm='npq-hero'" >> ~/.zshrc  # or ~/.bashrc or ~/.bash_profile
source ~/.zshrc  # or ~/.bashrc or ~/.bash_profile

在不安装包的情况下运行安全检查:

npq install express --dry-run

检查 npm lockfile 注入

npm install --save-dev lockfile-lint
npx lockfile-lint --path package-lock.json --type npm --allowed-hosts (如果修改了 node 镜像请填写镜像地址 registry.npmmirror.com) npm yarn --validate-https

CI/CD 集成

{
  "scripts": {
    "lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https",
    "preinstall": "npm run lint:lockfile"
  }
}

使用 npm ci

使用 npm ci 而不是 npm install 进行整体安装

npm ci

CI/CD 集成

# In your CI/CD pipeline
npm ci --only=production

避免盲目升级 npm 包

# 本地使用
npx npm-check-updates --interactive

Github Dependabot 和 Renovate 可以做到实时监控精细化升级依赖

# .github/dependabot.yml
# 配置 Dependabot 自动更新依赖
version: 2
updates:
  # 配置 GitHub Actions 的更新规则
  - package-ecosystem: "github-actions"
    directory: "/"  # 工作流文件通常在 .github/workflows 目录
    schedule:
      interval: "weekly"  # 每周检查一次更新
    target-branch: "develop"
    ignore:
      # 忽略 major 和 minor 级别更新
      - dependency-name: "*"
        update-types: ["version-update:semver-major", "version-update:semver-minor"]

  # 配置 npm 的更新规则
  - package-ecosystem: "npm"
    directory: "/"  # package.json所在目录
    schedule:
      interval: "weekly"
    target-branch: "develop"
    ignore:
      # 忽略 major 和 minor 级别更新
      - dependency-name: "*"
        update-types: ["version-update:semver-major", "version-update:semver-minor"]
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:recommended"],
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"]
    }
  ],
  "automerge": false,
  "automergeType": "pr",
  "labels": ["dependencies"],
  "baseBranchPatterns": ["develop"],
  "schedule": ["every weekday"],
  "recreateWhen": "never"
}

github.com/项目/security… 可以查看依赖警告

github.com/项目/network/… 可以查看 dependabot 运行情况

本地开发注意事项

.env 文件不要放入明文密码

在 .env 文件中使用密码引用地址

DATABASE_PASSWORD=op://vault/database/password
API_KEY=infisical://project/env/api-key

使用 secret manager CLI 在运行时注入密钥

# 1Password
op run -- npm start
# or more verbosely: 
op run --env-file="./.env" -- node --env-file="./.env" server.js

在开发容器中工作

  • 在您的项目中创建一个 .devcontainer/devcontainer.json 文件
  • 使用 VS Code 在开发容器中打开项目
{
  "name": "Node.js Dev Container",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
  "postCreateCommand": "npm ci"
}

后续资源

  "runArgs": [
    "--security-opt=no-new-privileges:true",
    "--cap-drop=ALL",
    "--cap-add=CHOWN",
    "--cap-add=SETUID",
    "--cap-add=SETGID"
  ],
  "containerEnv": {
    "NODE_OPTIONS": "--disable-proto=delete"
  },
  "forwardPorts": [9000]
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    host: "0.0.0.0",
    port: 9000,
  },
});
  • 使用自定义 Dockerfile 以增强安全性

npm 维护注意事项

为 npm 帐户启用 2FA

启用 2FA 进行身份验证和发布

npm profile enable-2fa auth-and-writes

仅适用于登录和配置文件更改

npm profile enable-2fa auth-only

使用出处证明发布

在 GitHub Actions 中使用出处发布

permissions:
  id-token: write
steps:
  - run: npm publish --provenance

注意:发布到带有出处的 npm 需要 npm CLI 9.5.0+ 和 GitHub Actions 或带有云托管运行器的 GitLab CI/CD。

使用 OIDC 发布

在 npmjs.com 上为包配置受信任的发布者,然后更新 CI/CD

GitHub Actions

permissions:
  id-token: write
steps:
  - run: npm publish

可信发布支持 GitHub Actions 和 GitLab CI/CD,并自动生成符合 OpenSSF 标准的出处证明。

减少包的依赖数量

将常见依赖项替换为原生 JavaScript

// Instead of lodash
const unique = [...new Set(array)];

// Instead of axios for simple requests
const response = await fetch(url);

// Instead of utility libraries
const isEmpty = obj => Object.keys(obj).length === 0;

JavaScript 提供了许多以前需要外部库的内置功能。在添加任何依赖项之前,请考虑维护成本、安全影响和捆绑包大小影响。