自社のビルドパイプラインで動いているパッケージ、すべて把握できていますか?ソースコードを一切書き換えなくても、開発チームが使うパッケージマネージャーの設定の盲点を突いて、悪意あるコードをビルド環境に混入させる攻撃が確認されています。
これが「依存関係コンフュージョン攻撃(Dependency Confusion Attack)」です。2021年にセキュリティ研究者のAlex Birsan氏がApple・Microsoft・PayPalなど大手企業への侵入実証で世界を驚かせ、以来、実際の攻撃に多用されています。
この記事では、依存関係コンフュージョン攻撃の仕組み・攻撃フロー・対策を、現場で使えるレベルで解説します。開発チームのセキュリティを担当する情シスの方、DevSecOpsを推進したい方に直結する内容です。
依存関係コンフュージョン攻撃とは?
依存関係コンフュージョン攻撃(Dependency Confusion Attack)は、パッケージマネージャーが「内部(社内)パッケージ」と「外部(公開)パッケージ」を解決する際の優先順位の設計上の盲点を突く攻撃手法です。
多くの企業は、社内専用ライブラリを内部レジストリ(Artifactory・Nexus・GitHub Packages等)で管理しています。問題は、npm・pip・Mavenなどのパッケージマネージャーは、デフォルト設定や設定ミスがある状態では、公開リポジトリ(npmjs.com・PyPI等)に同名かつより高いバージョン番号のパッケージが存在する場合、それを優先してダウンロードしてしまうことがあるという点です。
攻撃者はこの性質を次のように悪用します。
・内部パッケージ名の特定: GitHubに誤ってコミットされた設定ファイルや、エラーメッセージから社内パッケージ名を割り出す
・偽パッケージの公開登録: 同名のパッケージを公開レジストリに登録し、バージョン番号を社内版より大きく設定する
・自動インストール: ビルド時にパッケージマネージャーが「新しいバージョン」として悪意あるパッケージを自動取得する
・コード実行: インストール時に実行されるスクリプト(postinstall等)が攻撃者のコードを走らせる
CI/CDパイプラインやビルドサーバーで実行されるため、検知が難しく、侵入後の影響範囲も広くなります。
攻撃の仕組み(敵を知る)
1. 攻撃が成立するための前提条件
依存関係コンフュージョン攻撃が成立するには、以下の条件が重なる必要があります。
・社内専用パッケージを使っている: 内部レジストリで管理しているカスタムライブラリが存在する
・外部フォールバックが有効: パッケージマネージャーの設定で、内部にないパッケージを公開レジストリから取得する動作が有効になっている
・パッケージ名が外部から推測・特定できる: GitHub、求人票、エラーメッセージ等から内部パッケージ名が漏洩している
この3条件が揃ったとき、攻撃者は「コードを一行も書かずに」ビルド環境への侵入口を手に入れます。
2. 攻撃者はどうやって内部パッケージ名を調べるか
攻撃者が内部パッケージ名を入手する手段は複数存在します。
・誤コミット・誤公開された設定ファイル: `package.json`・`requirements.txt`・`pom.xml`・`go.mod` などがGitHubに誤ってアップロードされているケース
・エラーメッセージ: 「`company-internal-auth` が見つかりません」といったビルドエラーが外部に漏洩しているケース
・求人票・技術ブログ: 「内製ライブラリ〇〇を使った開発」のような情報が公開されているケース
・OSINTによる調査: 公開されたコードのimport文やdependencies宣言から芋づる式に特定するケース
Alex Birsan氏の実証では、エラーメッセージや公開ドキュメントから内部パッケージ名を取得し、35社以上への侵入実証に成功しました。
3. 攻撃フロー(概念説明)
# 【攻撃フロー概念説明】 # Step 1: 情報収集 # GitHubや求人票から内部パッケージ名 "company-auth-lib" を特定 # Step 2: 悪意あるパッケージを公開レジストリ(例: npmjs.com)に登録 # パッケージ名: company-auth-lib(社内名と同一) # バージョン: 99.0.0(社内バージョン 1.2.3 より大きい数値) # postinstall スクリプト: ホスト名・環境変数を攻撃者のサーバーへ送信 # Step 3: ターゲット企業のCI/CDパイプラインでビルドが実行される # npm install 実行 # → 内部レジストリに company-auth-lib v1.2.3 が存在 # → 公開レジストリに company-auth-lib v99.0.0 が存在 # → 設定次第で「より新しいバージョン」として公開版を取得してしまう # Step 4: インストール時に悪意あるpostinstallスクリプトが実行 # → ビルドサーバーの情報・シークレット・認証情報が流出 # → 攻撃者が内部ネットワークへの足がかりを入手
具体的な防御手順
1. パッケージマネージャーの解決順序を固定する
最も根本的な対策は、「内部レジストリを唯一の取得元」に設定し、外部への自動フォールバックを無効にすることです。
npmの場合(.npmrc)
# .npmrc: 内部レジストリのみを参照(外部フォールバックなし) registry=https://your-internal-registry.example.com/npm/ # スコープ付きパッケージを内部レジストリに固定 @mycompany:registry=https://your-internal-registry.example.com/npm/ # 外部アクセスを完全に禁止する場合は CI=true と組み合わせて管理する
Pythonの場合(pip.conf)
# /etc/pip.conf または ~/.pip/pip.conf [global] index-url = https://your-internal-registry.example.com/simple/ # 注意: extra-index-url を追加すると外部フォールバックが発生するため使用しない # NG例: extra-index-url = https://pypi.org/simple/
Artifactory・Nexusを使っている場合の注意点として、バーチャルリポジトリの解決順序で「内部リポジトリ」が「リモートリポジトリ(外部)」より優先されているか必ず確認してください。多くのデフォルト設定では外部が優先されています。
2. スコープ付き(名前空間付き)パッケージ名を採用する
npmでは `@mycompany/auth-lib` のようにスコープを付けることで、その名前空間の管理権を組織が保持できます。攻撃者が `@mycompany/` 配下に無断でパッケージを公開することはできません(スコープは組織認証が必要なため)。
# 危険な例(スコープなし・外部に同名登録される可能性あり) # "dependencies": { "company-auth-lib": "^1.0.0" } # 安全な例(スコープ付き・組織が名前空間を保有) # "dependencies": { "@mycompany/auth-lib": "^1.0.0" } # npmに組織スコープを登録する(1回限りの作業) npm org create mycompany
3. 公開レジストリで内部パッケージ名を「予約」する
内部パッケージ名が組織特有のスコープを持たない場合、防御的手段として、その名前を公開レジストリに「空のプレースホルダー」として先に登録することで、攻撃者が同名パッケージを登録できない状態にできます。
# package.json(プレースホルダー登録用) { "name": "company-auth-lib", "version": "0.0.1", "description": "Reserved package name. This is not for external use.", "license": "UNLICENSED", "private": false } # npmに公開するだけで名前空間が保護される npm publish --access public
4. ロックファイルとハッシュ検証を使う
`package-lock.json`(npm)・`Pipfile.lock`(Python/Pipenv)・`poetry.lock` などのロックファイルは、バージョン番号だけでなくパッケージのハッシュ値も記録します。ロックファイルを厳密に適用することで、想定外のバージョン取得を防げます。
# npm: ci コマンドでロックファイルを厳密適用(lockファイルと差異があるとエラー) npm ci # pip: ハッシュ検証を有効にしてインストール pip install --require-hashes -r requirements.txt # requirements.txt でハッシュを指定する例 # requests==2.31.0 \ # --hash=sha256:58cd2187423839 \ # --hash=sha256:... # pip-compile を使うとハッシュ付き requirements.txt を自動生成できる pip-compile --generate-hashes requirements.in
中小企業でも今日からできること
内部レジストリの構築やDevSecOpsの整備が進んでいない段階でも、すぐに実施できる対策があります。優先度の高い順に示します。
・ロックファイルの確認と厳密適用(ゼロコスト): `npm ci` や `pip install –require-hashes` を使い、既存のロックファイルでパッケージを固定する。ロックファイルが存在しない場合は今すぐ生成して管理対象に加える
・`.npmrc` / `pip.conf` の `extra-index-url` 削除: 外部フォールバックを引き起こす設定がないか5分で確認できる。設定ファイルを開いて `extra-index-url` や複数の `index-url` を確認する
・内部パッケージ名の棚卸しと公開レジストリでの予約: 社内で使っているカスタムパッケージ名を一覧化し、npmや PyPI に同名が登録されていないか確認する。見つかれば空のプレースホルダーで先に登録する
・無料の依存関係スキャンツールの導入: `npm audit`・`pip-audit`・Snyk の無料プランを使い、既存の依存パッケージに問題がないか定期確認する
また、使用しているパッケージの全体像を把握するためには、SBOM(ソフトウェア部品表)の整備も有効な手段です。どのパッケージが何のバージョンで使われているかを可視化することで、問題発生時の調査速度が大幅に上がります。
Linuxサーバー上でのパッケージ管理のベストプラクティスについては、姉妹サイトLinuxMaster.JPでも詳しく解説しています。
よくある誤解と注意点
【注意】「うちは外部パッケージしか使っていないから無関係」は誤り
外部のオープンソースだけを使っている場合でも、ビルドスクリプト・CI設定・カスタムプラグインなどを内部にのみ存在するファイルとして管理していれば、同種のリスクが生じます。また、依存関係コンフュージョンはサードパーティに委託している開発プロセス(受託開発・SES)のビルド環境にも存在し得ます。
【注意】「バージョン番号を固定すれば安全」は不十分
バージョン固定だけでは、攻撃者が同じバージョン番号でパッケージを上書き公開するタイポスクワッティング的な手法には対応できません。ロックファイルのハッシュ検証を必ず組み合わせてください。
【注意】「Artifactory / Nexus があれば安心」は設定次第
内部レジストリを導入していても、「リモートリポジトリ(外部へのプロキシ)」が有効になっていると、内部に存在しないパッケージは外部から取得されます。Artifactoryの場合、バーチャルリポジトリの「リポジトリ解決順序」で内部リポジトリが外部より先に解決されるよう必ず設定してください。
【注意】「攻撃は大企業だけが対象」は誤り
依存関係コンフュージョン攻撃は技術的なハードルが低く、誰でも試みることができます。中小企業であっても、開発チームや受託ベンダーが内部パッケージを使っている場合は同じリスクにさらされています。
本記事のまとめ
| 対策 | 効果 | 難易度 |
|---|---|---|
| ロックファイル+ハッシュ検証(npm ci / –require-hashes) | 特定バージョンのパッケージ差し替えを防止 | 低(設定変更のみ) |
| 外部フォールバック設定の削除(extra-index-url 削除等) | 侵入経路を根本から遮断 | 低(5分で確認可能) |
| スコープ付きパッケージ名の採用(@mycompany/) | 同名登録を困難にし名前空間を保護 | 中(命名変更が必要) |
| 公開レジストリでの内部パッケージ名の予約 | 攻撃者が同名パッケージを登録できなくなる | 低(1回の登録作業) |
| 内部レジストリの解決順序を内部優先に固定 | フォールバックそのものを排除する根本対策 | 中(設定変更+動作確認) |
依存関係コンフュージョン攻撃は「設定ミス」の問題に見えますが、実際には多くの組織のCI/CDパイプラインで潜在的に存在するリスクです。コードを改ざんせずに侵入できるため、検知が遅れやすい点が特に危険です。
まずはロックファイルの確認と `extra-index-url` などの外部フォールバック設定の削除から始めてください。5分で実施できる変更が、ビルド環境への侵入を防ぐ最初の壁になります。
また、依存関係コンフュージョンはサプライチェーン攻撃の一形態です。ソフトウェアの調達・開発・配布の全工程にわたるリスクを把握し、対策の優先度を判断することも重要です。
PR
サイバーセキュリティプログラミング 第2版(Justin Seitz・Tim Arnold/オライリー・ジャパン)
Pythonを使った実践的なセキュリティ技術を網羅した1冊。依存パッケージの安全な扱い方やビルドパイプラインのリスク分析など、DevSecOpsを推進したいエンジニアの入口として最適です。
