サプライチェーン攻撃の対策:npmエコシステムへの攻撃から学ぶ
概要¶
kawasima氏のscrapbox記事「サプライチェーン攻撃の対策」をHasegawa氏が紹介。2025年9月のShai-Hulud攻撃でnpmの正規パッケージが改ざんされ、認証情報が窃取された事件を背景に、具体的な対策をまとめたもの。
背景:何が起きたか¶
2025年9月 Shai-Hulud攻撃:
- ngx-bootstrap、ng2-file-upload、@ctrl/tinycolor 等の正規パッケージが改ざん
- postinstall フックに難読化済み bundle.js を埋め込み
- npm / GitHub / クラウドの認証情報を窃取
- webhook 経由で外部へ送信
- 最終的に数百パッケージが汚染される
→ 「信頼できる」パッケージも攻撃の踏み台になりうる
サプライチェーン攻撃の種類¶
1. パッケージの乗っ取り(Account Takeover)
メンテナのアカウントを奪いパッケージを改ざん
2. タイポスクワッティング
人気パッケージに似た名前の悪意あるパッケージを公開
例: 'lodash' → 'l0dash'
3. 依存関係の混入
間接依存(transitive dependency)に悪意あるコードを仕込む
4. ビルドツールの汚染
CI/CD パイプラインや build script を改ざん
5. postinstall フックの悪用
npm install 時に自動実行されるスクリプトに悪意あるコードを仕込む
対策¶
1. lock ファイルを必ずコミットする¶
# package-lock.json / yarn.lock / pnpm-lock.yaml を必ずコミット
# → インストールするバージョンをピン留めする
# NG: lock ファイルを .gitignore に追加
# OK: lock ファイルをリポジトリに含める
2. npm audit を CI に組み込む¶
# GitHub Actions の例
- name: Security audit
run: npm audit --audit-level=high
# high 以上の脆弱性があればビルドを失敗させる
3. postinstall スクリプトを無効化する¶
注意: 一部のパッケージは postinstall が必要なため、ホワイトリスト形式で管理する。
4. 依存関係のバージョン固定(ピン留め)¶
// package.json
{
"dependencies": {
// NG: "lodash": "^4.17.0" (マイナーアップデートが自動で入る)
// OK: "lodash": "4.17.21" (バージョンを固定)
}
}
Dependabot / Renovate で定期的に更新しつつ、テストを通してから更新する。
5. Supply Chain Levels for Software Artifacts (SLSA)¶
SLSA フレームワークの活用:
- ソースコードの来歴(provenance)を検証
- ビルド環境の完全性を保証
- 段階的なレベル(SLSA Level 1〜4)で対策強度を選択
Level 1: ビルドプロセスのスクリプト化
Level 2: バージョン管理 + ホステッドビルドサービス
Level 3: 監査可能なビルドサービス
Level 4: 2者による検証、密閉されたビルド環境
6. Subresource Integrity (SRI)¶
<!-- CDN から読み込むスクリプトのハッシュを検証 -->
<script
src="https://cdn.example.com/library.js"
integrity="sha384-xxxx..."
crossorigin="anonymous">
</script>
7. 依存関係の最小化¶
使っていないパッケージを定期的に削除:
npx depcheck # 使われていない依存を検出
1つの機能のために大きなライブラリを入れない:
例: 日付フォーマットだけのために moment.js 全体を入れない
→ date-fns の必要な関数だけ使う
8. プライベートレジストリの活用¶
npm の代替:
- GitHub Packages(プライベートリポジトリと統合)
- Artifactory / Nexus(エンタープライズ向け)
- Verdaccio(セルフホスト型)
→ 内部パッケージは社内レジストリに置き
外部からの改ざんリスクを下げる
9. 環境変数・シークレットの保護¶
# postinstall 攻撃で窃取されやすいもの
~/.npmrc # npm トークン
~/.ssh/ # SSH 秘密鍵
~/.aws/ # AWS 認証情報
.env # 環境変数ファイル
対策:
- CI/CD ではシークレットを環境変数として注入(ファイルに書かない)
- ローカル開発でも .env は暗号化ツールで管理
- 最小権限の原則(npm トークンは publish 権限のみ)
10. パッケージの公開者を確認する¶
# パッケージの公開者・メンテナを確認
npm info <package-name> maintainers
# ダウンロード数・最終更新日・GitHub スター数なども参考に
# → 急にメンテナが変わっていたら注意
検知・モニタリング¶
Socket.dev: npm パッケージの悪意あるコードを自動検出
Snyk: 脆弱性スキャン + 修正PR の自動作成
GitHub Advanced Security: secret scanning + dependency review
OpenSSF Scorecard: プロジェクトのセキュリティスコア評価
なぜ重要か / いつ使うか¶
- npm / yarn を使うすべてのプロジェクトに関係する
- 「有名パッケージだから安全」という思い込みは危険
- CI/CD パイプラインに npm audit と lock ファイルチェックを組み込む最低限の対策はすぐ実施できる
- セキュリティレビュー・新規パッケージ追加時のチェックリストとして活用