サプライチェーンセキュリティ

ソフトウェアの依存関係やビルドパイプラインを通じた攻撃を防ぐセキュリティ対策

セキュリティパッケージ管理

サプライチェーンセキュリティとは

ソフトウェアサプライチェーンセキュリティは、アプリケーションが依存するライブラリ、ビルドツール、CI/CD パイプライン、コンテナイメージなどを通じた攻撃を防ぐセキュリティ対策である。

現代のアプリケーションは大量のオープンソースライブラリに依存している。厄介なのは、自分が package.json に書いた依存の数と、実際に取り込まれるパッケージの数が一致しないことだ。依存がさらに依存を持つため、直接指定した数が数十でも取り込まれる総数は桁が変わる。そのどれか 1 つでも侵害されれば、他人の書いたコードが開発機と CI で実行される。

深刻さを広く知らせた事例は、機序がそれぞれ違う。2020 年の SolarWinds 事件は、ビルド環境そのものが侵害され、正規の署名が付いた更新にバックドアが混ざった型である。2021 年 12 月の Log4Shell (CVE-2021-44228・影響範囲は Log4j2 の 2.0-beta9 から 2.15.0) は攻撃ではなく脆弱性で、広く使われるライブラリ 1 つの欠陥が依存の連鎖を通じて無数の製品へ波及することを示した。2024 年 3 月の xz-utils (CVE-2024-3094) は、配布用の tarball にだけ仕込まれた細工がビルド過程で liblzma に埋め込まれるもので、リポジトリのソースを読むだけでは見つけられなかった。誰かが意図的に混ぜる攻撃と、作りの欠陥である脆弱性は、必要な対策が別になる。

攻撃ベクトル

依存関係の汚染

  • Typosquatting: 人気パッケージと紛らわしい名前でマルウェアを公開する。npm で報告された crossenvcross-env からハイフンを抜いただけの名前で、インストールした環境の環境変数を外部へ送信していた (GHSA-c2m4-w5hm-vqjw・全バージョンが登録抹消済み)。入口は打ち間違いだけでなく、記事や回答からのコピペも同じである
  • Dependency Confusion: 社内パッケージと同名のパッケージを公開レジストリに登録し、ビルド時に公開版が優先されることを悪用する
  • メンテナー権限の侵害・移譲: アカウントを乗っ取る型と、保守に疲れたメンテナーから公開権限を譲り受ける型がある。2018 年 11 月の event-stream では、権限を引き継いだ人物が新しい依存 flatmap-stream を追加し、特定の暗号通貨ウォレットアプリだけを狙う暗号化されたペイロードを実行させた (GHSA-mh6f-8j2x-4483・event-stream 3.3.6 が該当)。保守を引き受ける申し出は善意と見分けがつかず、技術的な検知が効きにくい

ビルドパイプラインの侵害

  • CI/CD の設定ファイルを改ざんし、ビルド成果物にバックドアを挿入する
  • GitHub Actions のサードパーティアクションにマルウェアが含まれる
  • ビルドサーバー自体が侵害される

コンテナイメージの改ざん

  • ベースイメージに脆弱性やマルウェアが含まれる
  • Docker Hub の非公式イメージにバックドアが仕込まれる

対策

ロックファイルの厳格な管理

# package-lock.json をコミットし、CI では npm ci を使う
npm ci  # package-lock.json と完全一致するインストール (npm install は使わない)

npm install はロックファイルを更新する可能性があるが、npm ci はロックファイルと完全一致しないとエラーになる。CI では必ず npm ci を使う。

SCA (Software Composition Analysis)

# 脆弱性チェック
npm audit --omit=dev  # 本番依存のみチェック

# 自動修正
npm audit fix

npm audit が見ているのはアドバイザリとして報告済みの脆弱性であり、今日混入したマルウェアや typosquatting は検出できない。CI に組み込み、Critical/High が検出されたらビルドを失敗させるのが基本形だが、2 点注意がある。npm audit fix は宣言済みの semver 範囲内でしか版を上げないため、修正が範囲外にしか無い場合は何も直らない。--force を付けると範囲を越えて上げる代わりに破壊的変更を引き込むので、CI で自動実行するものではない。

SBOM (Software Bill of Materials)

SBOM はアプリケーションが依存する全ライブラリのリスト (部品表) だ。脆弱性が公開されたとき、影響を受けるアプリケーションを即座に特定できる。

# CycloneDX 形式で SBOM を生成
npx @cyclonedx/cyclonedx-npm --output-file sbom.json

依存関係の最小化

不要な依存を削除し、攻撃対象面を縮小する。奇数判定だけを行う is-odd は、2026 年 8 月時点の 3.0.1 が判定のために is-number へ依存している。数行で書ける処理をパッケージで済ませると、こうして依存の木だけが伸びる。depcheck で未使用の依存を検出できる。

GitHub Actions のセキュリティ

# ❌ タグ指定 (改ざんリスクあり)
- uses: actions/checkout@v4

# ✅ コミットハッシュ指定 (参照先が後から動かない)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

サードパーティアクションはタグではなくコミットハッシュで固定する。タグは後から別のコミットへ付け替えられるためだ。これは想定上のリスクではない。2025 年 3 月、tj-actions/changed-files の v1 から v45.0.7 までのタグが攻撃者によって悪意あるコミットへ付け替えられ、ワークフローのシークレットがアクションのログに出力される状態になった (CVE-2025-30066)。

ただしハッシュ固定で保証されるのは「参照先が動かない」ことだけで、そのコミットの中身が安全である保証はない。固定した版は自動更新されないので、脆弱性修正を取り込む手段 (Dependabot 等での更新 PR) を別に用意しないと、古いまま放置される方の危険が育つ。

AWS での対策

  • ECR イメージスキャン: 基本スキャンはプッシュ時または手動実行で、対象は OS パッケージの脆弱性である。言語パッケージ (npm や pip で入れた依存) まで見て継続的に再評価させたい場合は、Amazon Inspector と連携する拡張スキャンに切り替える
  • CodeArtifact: プライベートレジストリ。ただし直接公開と公開リポジトリからの取り込みの両方を許した状態では依存の置き換え (Dependency Confusion) が成立し得るため、パッケージオリジンコントロールで「この名前は社内公開のみ」と経路を絞る設定が要る
  • Inspector: Lambda 関数が使う依存パッケージの脆弱性を継続的に検出する。EC2 や ECR のイメージも同じ仕組みで扱える

守る場所と手段の対応

対策はどの攻撃ベクトルに効くかで選ぶ。ロックファイルは取り込む版を固定するが、固定した版が最初から悪意を持っていれば効かない。署名検証は配布経路での差し替えを弾くが、正規のメンテナーが自分で公開した悪意あるコードは通す。1 つで足りる手段は無く、下の表は互いの穴を埋める組み合わせとして読む。

対策ツール説明
依存脆弱性スキャンnpm audit, Snyk既知の脆弱性を検出
SBOMSyft, Trivyソフトウェア部品表を生成
ロックファイルpackage-lock.jsonバージョンを固定
署名検証Sigstoreパッケージの署名を検証
最小権限GitHub Actions permissionsワークフローの権限を制限

これらはいずれも、今そこにある物を検査する側の手段だ。もう一方の軸として、成果物がどこで何から作られたかを記録して検証する来歴 (provenance) の整備が進んでいる。SLSA は要求水準を Build トラックの L1 (来歴が存在する) / L2 (ホストされたビルド基盤が署名した来歴) / L3 (ビルド基盤自体が堅牢化されている) に分けており、2026 年 8 月時点の仕様は v1.0 である。npm では GitHub Actions などの対応 CI から npm publish --provenance で来歴を付けられ、trusted publishing を使う場合はフラグなしで付く。利用側はその来歴から、パッケージが公開元のリポジトリとコミットから実際にビルドされたかを確かめられる。

理論と実装の両面から学ぶなら関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事