正在加载,请稍候…

依赖安全:供应链攻击与NPM/PyPI包安全

防范供应链攻击和恶意依赖。学习依赖审计、锁文件、私有仓库、SBOM生成和CI安全扫描。

依赖安全:供应链攻击与NPM/PyPI包安全

依赖安全与供应链

NPM安全审计

# 检查漏洞
npm audit
npm audit --audit-level=high  # 仅在高/严重级别时失败

# 自动修复(如可能)
npm audit fix

# 详细JSON报告
npm audit --json > audit-report.json

# 检查过时的包
npm outdated

# 使用socket.dev进行深度分析
npx socket npm install lodash

依赖安全:供应链攻击与NPM/PyPI包安全插图

锁文件最佳实践

# 始终提交锁文件
git add package-lock.json  # 或 yarn.lock / pnpm-lock.yaml

# 在CI中使用 --frozen-lockfile
npm ci                    # 严格遵循 package-lock.json
yarn install --frozen-lockfile
pnpm install --frozen-lockfile

# 验证锁文件完整性
npm ci --audit

依赖固定版本

{
  "dependencies": {
    "express": "4.18.2",  // 固定版本 - 好
    "lodash": "^4.17.21", // ^ 允许次要/补丁版本 - 可接受
    "react": "~18.2.0",   // ~ 仅允许补丁版本 - 可接受
    "some-pkg": "*"       // 通配符 - 危险
  }
}

依赖安全:供应链攻击与NPM/PyPI包安全插图

GitHub Actions安全扫描

# .github/workflows/security.yml
name: Security Scan

on: [push, pull_request]

jobs:
  dependency-audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: NPM Audit
        run: npm audit --audit-level=high

      - name: Snyk vulnerability scan
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

      - name: OWASP Dependency Check
        uses: dependency-check/Dependency-Check_Action@main
        with:
          project: 'myapp'
          path: '.'
          format: 'HTML'
          args: --failOnCVSS 7

  secret-scanning:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # 完整历史用于秘密扫描

      - name: Gitleaks scan
        uses: gitleaks/gitleaks-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  sast:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: CodeQL Analysis
        uses: github/codeql-action/analyze@v3
        with:
          languages: javascript, typescript

SBOM(软件物料清单)

# 使用CycloneDX生成SBOM
npm install -g @cyclonedx/cyclonedx-npm
cyclonedx-npm --output-file sbom.json

# 使用Syft生成SBOM
syft packages . --output spdx-json=sbom.spdx.json

# 扫描SBOM与漏洞数据库对比
grype sbom:./sbom.json

# 将SBOM存储在CI工件中

依赖安全:供应链攻击与NPM/PyPI包安全插图

私有包仓库

# 使用Verdaccio作为私有npm仓库
npm install -g verdaccio
verdaccio

# 配置npm使用私有仓库
npm set registry http://localhost:4873/

# 项目的.npmrc
@mycompany:registry=https://npm.company.com
//npm.company.com/:_authToken=${NPM_TOKEN}

# 阻止同名的公共包(命名空间抢注预防)
# package.json
{
  "name": "@mycompany/internal-lib",  // 作用域包
  "private": true
}

预提交秘密检测

# 安装pre-commit
pip install pre-commit

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/Yelp/detect-secrets
    rev: v1.4.0
    hooks:
      - id: detect-secrets
        args: ['--baseline', '.secrets.baseline']

  - repo: https://github.com/zricethezav/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

# 初始化
pre-commit install
pre-commit run --all-files

域名抢注检测

import requests
from difflib import SequenceMatcher

def check_typosquatting(package_name: str, threshold: float = 0.85) -> list:
    """检查包名是否与流行包名相似到可疑程度。"""
    popular_packages = [
        "express", "react", "lodash", "axios", "moment",
        "webpack", "babel", "eslint", "prettier", "typescript"
    ]

    suspicious = []
    for popular in popular_packages:
        similarity = SequenceMatcher(None, package_name, popular).ratio()
        if similarity > threshold and package_name != popular:
            suspicious.append({
                "package": package_name,
                "similar_to": popular,
                "similarity": similarity,
            })
    return suspicious

# 安装前检查
result = check_typosquatting("expres")  # 缺少's'
if result:
    print(f"警告:可能的域名抢注:{result}")

安全策略

# .github/SECURITY.md 模板要点:
# - 支持的版本表格
# - 漏洞报告流程
# - 响应时间线(24小时确认,7天修复)

# Dependabot自动更新
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "security-team"
    labels:
      - "security"
    open-pull-requests-limit: 10