除外パターン機能に加えて:優先順位付けされた安全なリポジトリ
数週間前にニュースになった名前空間シャドウイング、別名「依存関係かく乱」攻撃を覚えているでしょうか。JFrog Artifactoryの除外パターン機能については、その時にブログで紹介しましたが、これはずっと前からあったもので、この種の攻撃からユーザーを守るためのものでした。
この話題がニュースになったことで、除外パターン機能に注目が集まり、ビルドの安全性が高まることはもちろんですが(今も使われていますよね?)、このアプローチの欠点も浮き彫りになりました。
私たちはお客様からのフィードバックをいただきました。除外パターンは機能し、実装も簡単です。但し、内部ライブラリが小さな共通の命名パターンに準拠していない場合、多くの除外ルールを設定しなければならず、パフォーマンスに影響を与える可能性があります。これはリポジトリレベルでの管理が必要でしたが、Artifactory 7.16.3からローカルまたはリモートのリポジトリに「優先解決」フラグを立てることができるようになりました。
概要:このチェックボックスをプライベートパッケージを含むリポジトリに対して有効にした場合、Artifactoryはそれらのパッケージの新しいバージョンを検索しない。
技術的な詳細がお知りになりたい方のために、その仕組みをご説明します。
パッケージマネージャが依存関係を要求する場合、(一般的なケースでは)まずメタデータ(利用可能な全てのバージョンリスト)を要求し、次に(依存関係の定義に基づいて)どのバージョンが必要かを判断し、特定のファイルを要求します。
パッケージマネージャがArtifactoryのバーチャルリポジトリを利用するように設定されている場合、リポジトリはローカルおよびリモートリポジトリのセットを含みます。Artifactoryは以下の2つのルールに基づいて、全てのリポジトリの全てのファイルを順に解析し、クライアント用のメタデータを準備します。(1)バーチャルリポジトリで設定した解決順、(2)ローカルリポジトリは常にリモートリポジトリよりも先に問い合わせを実施。
いくつかのシナリオを考えてみましょう。
プロモーションパイプラインのためのローカルリポジトリのセットとセントラルレジストリをプロキシするリモートリポジトリがあり、これらはすべて1つのバーチャルリポジトリに含まれています。バーチャルリポジトリの設定で定義されている解決順は以下の通りです。
- ローカル本番用リポジトリ
- ローカルステージング用リポジトリ
- ローカル開発用リポジトリ
- リモートリポジトリ
リモートリポジトリをローカルリポジトリよりも上位に配置した場合でも、心配ありません。Artifactoryは常にローカルリポジトリから先に解決するように順番を入れ替えます。この設定でいくつかのシナリオを実行してみましょう。
シナリオ1: 外部依存関係のバージョンをリストアップ
- ユーザーが依存関係を定義した「external-package」のバージョン~1.0.0(1.0.0と後方互換性のある全バージョン、つまり2.0.0を含まない全バージョン)
- クライアントがパッケージ「external-package」のメタデータを1.0.0から2.0.0を含まない範囲で要求する。
- Artifactoryは3つのローカルリポジトリをすべてチェックするが「external-package」のメタデータが存在しないため、検索できない。
- Artifactoryはリモートリポジトリをチェックし、「external-package」(バージョン1.1.0や1.2.0など)のメタデータを検索する。
- メタデータのマージは不要で検索された両バージョンを含むセントラルレジストリのメタデータが返される。
シナリオ2: 異なるリポジトリにある異なるバージョンの内部依存関係のバージョンをリストアップ
- ユーザーが依存関係を定義した「external-package」のバージョン~1.0.0(1.0.0と後方互換性のある全バージョン、つまり2.0.0を含まない全バージョン)
- クライアントがパッケージ「internal-package」のメタデータを1.0.0から2.0.0を含まない範囲で要求する。
- Artifactoryは3つのローカルリポジトリをチェックし、3つのリポジトリに異なるメタデータのリストを検索(本番用にはバージョン1.1.0、1.2.0、1.3.0、ステージング用にはバージョン1.4.0、1.5.0、開発用にはバージョン1.6.0が存在)
- Artifactoryがリモートリポジトリをチェックし、キャッシュとセントラルレジストリに存在しないため、「internal-package」は検索できない。
- Artifactoryはメタデータをマージし、バージョン1.1.0から1.6.0までの全バージョンをバーチャルリポジトリから取得するリストを作成する。
シナリオ3: 名前空間シャドウイング攻撃
- 攻撃者は「internal-package」の悪意のあるバージョンをバージョン1.7.0として外部リポジトリにアップロードする。
- ユーザーが依存関係を定義した「external-package」のバージョン~1.0.0(1.0.0 と後方互換性のある全バージョン、つまり2.0.0までの全バージョン)
- クライアントがパッケージ「internal-package」のメタデータを1.0.0から2.0.0の範囲で要求する。
- Artifactoryは3つのローカルリポジトリをチェックし、3つのリポジトリに異なるメタデータのリストを検出する(本番用にはバージョン1.1.0、1.2.0、1.3.0、ステージング用にはバージョン1.4.0、1.5.0、開発用にはバージョン1.6.0が含まれる)
- リモートリポジトリには除外パターンが定義されていないため、Artifactoryがチェックした場合、「internal-package」のメタデータが検索され、悪意のあるバージョン1.7.0がリストアップされる。
- Artifactoryはメタデータをマージし、バージョン1.1.0から1.7.0までの全バージョンがバーチャルリポジトリから取得できるリストを作成する。
- クライアントは最新バージョン(1.7.0)を取得し、ハッキングされる。
リポジトリに優先解決フラグを設定した場合、バーチャルリポジトリを解決する際、解決順が優先されます。リポジトリに優先順位を設定した場合、このフィールドが設定されたリポジトリからのみメタデータがマージされ、シナリオ3のステップ5はキャンセルされます(悪いシナリオ3を良いシナリオ2に効果的に変換します)。そのため、返されるメタデータには6つのバージョンしか表示されないため、クライアントは悪意のあるバージョン1.7.0のことを意識せず、それを要求することもありません。
当然、リポジトリを優先解決するように設定した場合でも(最初の例のように)アーティファクトがどのローカルリポジトリでも見つからない場合は(優先解決が未設定の場合)他のリポジトリの検索が行われます(セントラルレジストリで「external-package」を検索する)。
ほとんどの場合は優先度の設定はローカルリポジトリで行いますが、信頼できるArtifactoryインスタンス(別の開発サイトなど)をプロキシするリモートリポジトリが存在する場合もあるため、優先度の設定はリモートリポジトリでも行えます。
JFrog Artifactoryを最新版にアップグレードし、内部の依存関係があるリポジトリを「優先解決」とマークし、名前空間シャドウイング攻撃から保護することをお勧めします。内部依存関係を名前空間(または少なくとも命名規則)でスコープし、それらに除外パターンを使用することを強くお勧めします。