サプライチェーン
依存関係の混乱(Dependency Confusion)とは
依存関係の混乱(Dependency Confusion)とは、ビルドが社内のプライベートパッケージの代わりに、同じ名前の攻撃者の公開パッケージをインストールしてしまう攻撃です。誰も入力ミスをしていません。攻撃者は社内パッケージの名前を知り、それを大きなバージョン番号で公開レジストリに公開するだけでよく、あとは設定の誤ったビルドがやってくれます。
更新日
依存関係の混乱攻撃の仕組み
- 社内の名前を見つける。プライベートパッケージの名前は、公開コード、JavaScriptバンドル、エラーメッセージ、リポジトリに残されたマニフェストなどから漏れます。
- 同じ名前で公開する。攻撃者はnpm、PyPI、その他の公開レジストリに、非常に大きなバージョン番号でその名前を登録します。
- ビルドを待つ。社内レジストリと公開レジストリの両方を確認するよう設定されたパッケージマネージャーは、候補を2つ見つけ、バージョンの大きいほうを選びます。
- 社内で実行される。パッケージのインストールスクリプトが開発者のマシンやCIランナー上で実行され、そこにあるものすべてにアクセスできます。
この名前を付けた研究
2021年2月、セキュリティ研究者のAlex Birsanがこの手法を公表しました。彼はバグバウンティプログラムの下で、または許可を得て、Apple、Microsoft、PayPalを含む35以上の組織の内部でこの手法を使ってコードを実行させていました。テストした3つの言語すべてで成功し、公表から数日のうちに攻撃者が模倣し始めました。
なぜ起きるのか
根本原因は、複数のレジストリを同等に扱うパッケージマネージャーです。典型例はPythonです。pipの--extra-index-urlはPyPIの隣に2つ目のソースを追加し、同じ名前の公開パッケージが見つかればそれをインストールすることがあります。
# Unsafe for private packages: both indexes are candidates
pip install --extra-index-url https://pypi.internal.example/simple my-internal-lib
# Safer: one index you control, which proxies public packages
pip install --index-url https://pypi.internal.example/simple my-internal-lib
npmでもスコープのない社内名には同じ問題がありますが、自社のレジストリに紐付けたスコープを使えば回避できます。
# .npmrc: everything under @acme comes only from your registry
@acme:registry=https://npm.internal.example/
依存関係の混乱を防ぐ方法
- 信頼できる情報源を1つにする。ビルドの参照先を、公開パッケージをプロキシする単一の社内レジストリにし、社内名が公開側で解決されないよう設定します。
-
スコープや名前空間を使う。公開レジストリで
@acmeのようなスコープを所有し、それをプライベートレジストリに対応付けます。 - 名前を予約する。社内パッケージ名を公開レジストリに登録し、他者が登録できないようにします。
-
固定して検証する。ロックファイルをコミットし、pipの
--require-hashesなどのハッシュチェックを使って、異なるパッケージならインストールが失敗するようにします。ロックファイルにできること、できないことをご覧ください。 - ビルドの接続先を制限する。ビルドが自社のレジストリにしか到達できなければ、攻撃者のパッケージはそもそも取得できません。GitHub Actionsのエグレスポリシーをご覧ください。
- 何が漏れているかを確認する。公開コードやクライアントのバンドルで、社内パッケージ名を検索します。
依存関係の混乱とタイポスクワッティングの違い
タイポスクワッティングは、人が公開パッケージの名前を打ち間違えることを利用します。依存関係の混乱は、プライベートパッケージの正確な名前を使い、ビルドの設定を利用します。どちらも行き着く先は同じで、攻撃者のコードがビルドの中で実行されます。ほかの攻撃との関係はサプライチェーン攻撃とはをご覧ください。
影響を受けたかどうかを確認する方法
公開レジストリから解決された社内パッケージ名や、社内レジストリに存在しないバージョンを探します。問われているのはビルド中にパッケージが実際にどこから来たかなので、ロックファイルだけでこれを確認するのは困難です。
CRACIでできること
CRACIは、パッケージが取得される時点で機能します。GitHub Actionsのランナーとして、レジストリを型付きのソースとして扱うエグレスポリシーを適用するため、ビルドの取得元を許可したレジストリに限定できます。また、各ジョブが取得したすべてのパッケージをSBOMに記録するため、ビルドに何が入ったかを確認できます。CRACIはパッケージが悪意あるものかどうかを検出しないため、レジストリの設定を第一の防御線として維持してください。ソフトウェアサプライチェーンセキュリティのベストプラクティスをご覧ください。
依存関係の混乱:よくあるご質問
依存関係の混乱攻撃とは何ですか?
プライベートパッケージと同じ名前の公開パッケージが誤ってインストールされる攻撃です。パッケージマネージャーが両方のレジストリを確認し、バージョンの大きいほうを選ぶために起こります。
依存関係の混乱とタイポスクワッティングはどう違いますか?
タイポスクワッティングは、誰かが公開パッケージ名を打ち間違えることを利用します。依存関係の混乱は、プライベートパッケージの正確な名前を使い、公開レジストリを確認するビルド設定を利用します。
依存関係の混乱はどう防げばよいですか?
単一の社内レジストリ、スコープ付きのパッケージ名、ハッシュチェック付きのロックファイル、そしてビルドが到達できるレジストリを制限するルールを使います。社内名を公開側で予約しておくことも有効です。
--extra-index-urlは安全ですか?
プライベートパッケージには安全ではありません。両方のインデックスが候補になるため、同じ名前の公開パッケージがインストールされる可能性があります。自社で管理する1つのインデックスを--index-urlで指定してください。
依存関係の混乱を発見したのは誰ですか?
セキュリティ研究者のAlex Birsanが、バグバウンティプログラムの下で、または許可を得て35以上の組織に対してこの手法を使った後、2021年2月に公表しました。