SJ blog
security
A

信頼度ランク

S 公式ソース確認済み
A 成功実績多数・失敗例少数
B 賛否両論
C 動作未確認・セキュリティリスク高
Z 個人所感

サプライチェーン攻撃と依存関係の脆弱性管理

npmパッケージへの悪意ある改ざん・依存関係の脆弱性など、サプライチェーン攻撃の手口と対策を解説。Dependabot・Socket・署名検証・lockfileの重要性を説明します。

一言結論

サプライチェーン攻撃はlockfileのコミット・npm ciの使用・Dependabotによる自動更新・npm auditのCI組み込みという4つの基本対策を実施するだけで、現実的なリスクの大部分を低減できる。

サプライチェーン攻撃とは

直接のコードではなく、コードが依存する「サプライチェーン」を攻撃する手法

典型的な手口:
1. 人気パッケージにマルウェアを仕込んで公開(typosquatting含む)
2. メンテナのアカウントを乗っ取ってパッケージを改ざん
3. 悪意あるパッケージを依存として潜り込ませる
4. パッケージの廃止・reuse によるリネーム攻撃

実際の事例:

  • event-stream事件(2018): 人気パッケージに暗号通貨を盗むコードが挿入
  • colors.js・faker.js(2022): 作者が意図的に壊してDOSコードを追加
  • XZ Utils(2024): Linux のコアライブラリにバックドアが仕込まれる寸前

対策1: Lockfile を必ずコミットする

# ✅ package-lock.json / yarn.lock / pnpm-lock.yaml をコミットする
# これにより、依存関係の正確なバージョンが固定される

# ❌ npm install(lockfileを無視して最新を取得する可能性)
npm install  # package.json の範囲内で最新をインストール

# ✅ CI では npm ci を使う(lockfileに完全に従う)
npm ci

対策2: Dependabot / Renovate で脆弱性を自動検出

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    groups:
      dev-deps:
        patterns: ["eslint*", "prettier*", "@types/*"]
    ignore:
      - dependency-name: "lodash"
        update-types: ["version-update:semver-major"]
    security-updates-only: false

対策3: npm audit を CI に組み込む

# .github/workflows/security.yml
- name: Security audit
  run: |
    npm audit --audit-level=high
    # high 以上の脆弱性があればビルドを失敗させる
# 手動で確認
npm audit
npm audit --json | jq '.vulnerabilities | to_entries[] | select(.value.severity == "critical")'

# 修正可能なものを自動修正
npm audit fix

# 破壊的変更が伴う場合も強制修正(注意して使う)
npm audit fix --force

対策4: パッケージの信頼性を確認する

インストール前にパッケージを調査する習慣を:

# socket.dev でパッケージの安全性を確認
npx socket info <package-name>

# npm のダウンロード数・更新頻度を確認
npm show <package-name> time.modified
npm show <package-name> downloads.weekly

確認する観点:

  • ダウンロード数(低いものは要注意)
  • 最終更新日(長期放置は危険)
  • メンテナ数(1人だとリスク高)
  • リポジトリに Issue・PR が活発か

対策5: package.json の overrides でバージョンを固定

推移的な依存関係(依存の依存)に脆弱性がある場合:

{
  "overrides": {
    "lodash": "4.17.21",
    "minimist": "1.2.8"
  }
}

対策6: .npmrc でパブリッシュ先を制限

# .npmrc
registry=https://registry.npmjs.org/

# プライベートスコープはプライベートレジストリに
@myorg:registry=https://npm.mycompany.com/

# package-lock.json の整合性チェックを強制
package-lock=true

対策7: npm の provenance(来歴)を確認

2023年から npm は provenance attestation をサポートしています:

# パッケージの署名と来歴を確認
npm audit signatures

# 来歴付きでパブリッシュ(GitHub Actions から)
npm publish --provenance

対策8: 依存関係の最小化

原則: 依存は少ないほど良い

よくある過剰依存の例:
❌ is-even(0+1本)を使う for 偶数チェック
✅ n % 2 === 0 をそのまま書く

❌ left-pad
✅ String.prototype.padStart(ネイティブ)

まとめ

優先度対策
必須lockfile をコミット・CI で npm ci を使う
必須npm audit を CI に組み込む
推奨Dependabot / Renovate で自動更新
推奨新規パッケージ追加時は socket.dev で確認
推奨依存関係を必要最小限にする

参考: Socket Security / OpenSSF Best Practices / npm audit 公式