セキュリティで保護されたソフトウェア サプライ チェーンのベスト プラクティス

オープンソースはあらゆる場所にあります。 多くの独自のコードベースやコミュニティ プロジェクトに含まれています。 現在、組織や個人が確認しなければならないのは、オープンソース コードを使用しているかどうかではなく、どのようなオープンソース コードをどれくらい使用しているかということです。

ソフトウェア サプライ チェーンの内容を把握していないと、上流の依存関係のいずれかに致命的な脆弱性があった場合、企業やその顧客が潜在的な侵害に対して脆弱になる可能性があります。 このドキュメントでは、"ソフトウェア サプライ チェーン" という用語の意味、その重要性、プロジェクトのサプライ チェーンをベスト プラクティスで保護する方法について詳しく説明します。

2020年オクトーバースの現況 - オープンソース

依存関係

ソフトウェア サプライ チェーンとは、ご利用のソフトウェアに組み込まれるすべてのものと、それがどこから来たのかを示すために使用される用語です。 それは、ソフトウェア サプライ チェーンが依存している依存関係と、依存関係のプロパティです。 依存関係とは、ソフトウェアが実行する必要があるものです。 コード、バイナリ、またはその他のコンポーネントと、その取得元の場所 (リポジトリやパッケージ マネージャーなど) である場合があります。

それには、誰がコードを作成したか、いつ投稿されたか、セキュリティの問題がどのように確認されたか、既知の脆弱性、サポートされているバージョン、ライセンス情報、およびプロセスの任意の時点でそれに関係するすべてのものが含まれます。

また、サプライ チェーンには、ビルドとパッケージ化のスクリプトや、アプリケーションが依存するインフラストラクチャを実行しているソフトウェアなど、1 つのアプリケーションの範囲を超えるスタックの他の部分も含まれています。

脆弱性

現在、ソフトウェアの依存関係は広く利用されています。 プロジェクトの機能に多数のオープンソースの依存関係を使用したので、自分で作成する必要がなかった、というのは非常によくあることです。 これは、アプリケーションのほとんどの部分が、自分で作成したものではないコードで構成されていることを意味する可能性があります。

The State of the Octoverse 2020 - Dependenciesオクトバースの状態2020 - 依存関係

サードパーティやオープンソースの依存関係に含まれる可能性のある脆弱性は、おそらく、自分で作成したコードほど厳しく制御することができない依存関係であり、これによりサプライ チェーンに潜在的なセキュリティ リスクが生じる可能性があります。

このような依存関係のいずれかに脆弱性がある場合、それを使う側にも脆弱性がある可能性があります。 使う側が知ることなく依存関係のいずれかが変更される可能性があるということは、恐ろしいことです。 依存関係に脆弱性が存在していて、今は悪用できない場合でも、将来悪用される可能性があります。

多数のオープンソース開発者やライブラリ作成者が作ったものを利用できるということは、何千もの知らない人が自分の運用コードに直接、効果的に寄与できることを意味します。 自分の製品が、ソフトウェア サプライ チェーンを通じて、修正プログラムが適用されていない脆弱性、悪意のない誤り、さらには依存関係に対する悪意のある攻撃からの影響を受けます。

サプライ チェーンの侵害

サプライ チェーンの従来の定義は、製造業が基になっています。それは、何かを製造して供給するために必要なプロセスのチェーンです。 それには、計画、材料の供給、製造、小売が含まれます。 ソフトウェア サプライ チェーンも似ていますが、材料ではなくコードである点が異なります。 製造ではなく開発です。 鉱石を地中から掘り出す代わりに、コードはサプライヤー、市販品、オープンソースから供給され、通常、オープンソースのコードはリポジトリから取得されます。 リポジトリからコードを追加するということは、製品でそのコードの依存関係を取得することを意味します。

ソフトウェア サプライ チェーン攻撃の一例として、悪意のあるコードが依存関係に意図的に追加され、その依存関係のサプライ チェーンを使用して犠牲者にコードが配布される場合があります。 サプライ チェーン攻撃は現実のものです。 サプライ チェーンを攻撃する方法は多数あります。新しい共同作成者として悪意のあるコードを直接挿入したり、他の人が気付かないうちに共同作成者のアカウントを乗っ取ったり、さらには署名キーを侵害して依存関係の正式な一部ではないソフトウェアを配布することさえあります。

ソフトウェア サプライ チェーン攻撃は、それ自体が最終的な目標であることはあまりなく、攻撃者がマルウェアを挿入したり、後でアクセスできるようにバックドアを用意したりするための機会の始まりです。

2020年Octoverseの状態 - 脆弱性のライフサイクル

修正プログラムが適用されていないソフトウェア

現在、オープンソースの使用は広く行われており、近いうちに下火になるとは思われません。 オープンソース ソフトウェアの使用が止まることがないとすると、修正プログラムが適用されていないソフトウェアがサプライ チェーンのセキュリティに対する脅威になります。 では、プロジェクトの依存関係に脆弱性があるというリスクに対処するには、どうすればよいでしょうか。

  • 環境内にあるものを把握する。 これには、依存関係とすべての推移的な依存関係を検出して、脆弱性やライセンスの制限など、それらの依存関係のリスクを理解する必要があります。
  • 依存関係を管理する。 新しいセキュリティ脆弱性が発見されたら、影響を受けるかどうかを判断し、受ける場合は、利用可能な最新バージョンとセキュリティ修正プログラムに更新する必要があります。 これは、新しい依存関係が導入される変更を確認したり、古い依存関係を定期的に監査したりする場合に特に重要です。
  • サプライ チェーンを監視する。 そのためには、依存関係を管理するために設けられている制御を監査します。 これは、依存関係に対してより制限の厳しい条件を適用するのに役立ちます。

2020年オクトバースの現状 - 勧告

以降では、NuGet と GitHub に用意されているさまざまなツールと手法について説明します。それらを使用して、プロジェクト内の潜在的なリスクに対処できます。

環境内にあるものを把握する

既知の脆弱性を持つパッケージ

パッケージ消費者 | パッケージ作成者

.NET 8 と Visual Studio 17.8 によって NuGetAudit が追加されました。この機能は、復元中に既知の脆弱性を持つ直接パッケージに関する警告を開発者に表示します。 .NET 9 と Visual Studio 17.12 は、推移パッケージについても警告するように既定値を変更しました。

NuGetAudit には既知の脆弱性データベースを提供するソースが必要であるため、パッケージ ソースとして nuget.org を使用していない場合は、監査ソースとして追加する必要があります。

NuGet から警告を受けた時点で、この脆弱性は一般に知られています。 攻撃者は、この公開情報を使用して、アプリケーションにパッチを適用していないターゲットに対する攻撃を開発できます。 そのため、プロジェクトが使用しているパッケージに既知の脆弱性があることを示す警告が表示された場合は、迅速に対処する必要があります。

NuGet の依存関係グラフ

📦 パッケージ消費者

プロジェクトでの NuGet の依存関係は、該当するプロジェクト ファイルを直接見ることで確認できます。

通常、これは次の 2 つの場所のいずれかにあります。

NuGet の依存関係の管理に使用する方法に応じて、Visual Studio のソリューション エクスプローラーまたは NuGet パッケージ マネージャーを使用して依存関係を直接見ることもできます。

CLI 環境の場合は、dotnet list package コマンドを使用して、プロジェクトまたはソリューションの依存関係の一覧を表示できます。 dotnet nuget why コマンドを使用すると、推移的パッケージ (プロジェクトから直接参照していないパッケージ) がプロジェクトのパッケージ グラフに含まれている理由も確認できます。

NuGet の依存関係を管理する方法についての詳細は、以下の資料を参照してください。

GitHub の依存関係グラフ

パッケージ消費者 | パッケージ作成者

GitHub の依存関係グラフを使用して、プロジェクトが依存しているパッケージと、それに依存するリポジトリを確認できます。 これは、その依存関係で検出された脆弱性を確認するのに役立ちます。

GitHub リポジトリの依存関係の詳細については、こちらのドキュメントを参照してください

依存関係のバージョン

パッケージ消費者 | パッケージ作成者

依存関係のサプライ チェーンをセキュリティで保護するには、すべての依存関係とツールが最新の安定したバージョンに定期的に更新される必要があります。それらには、最新の機能と、既知の脆弱性に対するセキュリティ修正プログラムが含まれることが多いためです。 依存関係には、依存しているコード、利用するバイナリ、使用するツール、その他のコンポーネントが含まれる場合があります。 これには以下が含まれます。

依存関係を管理する

NuGet の非推奨および脆弱な依存関係

パッケージ消費者 | パッケージ作成者

dotnet CLI を使用して、プロジェクトまたはソリューション内にある既知の非推奨または脆弱な依存関係を一覧表示できます。 dotnet list package --deprecated または dotnet list package --vulnerable コマンドを使用すると、既知の非推奨項目または脆弱性の一覧が提供されます。 NuGetAudit は、既知の脆弱性を含む依存関係について警告できます。ソースが脆弱性データベースを提供している場合は、既定で有効です。

GitHub の脆弱な依存関係

パッケージ消費者 | パッケージ作成者

プロジェクトが GitHub でホストされている場合、GitHub Securityを利用してセキュリティ脆弱性やエラーを検出できます。これらは、Dependabot がコードベースに対してプルリクエストを作成して修正します。

脆弱な依存関係を導入される前に検出することは、“Shift Left”の活動の1つの目標です。 ライセンス、推移的な依存関係、依存関係の経過期間など、依存関係に関する情報を取得できるようにすることは、そのために役立ちます。

Dependabot のアラートとセキュリティ更新プログラムの詳細については、以下のドキュメントをご確認ください

NuGet の構成

📦 パッケージ消費者

プロジェクト リポジトリのルートに nuget.config ファイルを追加します。 これは、再現性が向上し、異なるユーザーが同じ NuGet 構成を持つことが保証されるため、ベスト プラクティスと見なされます。 clear要素を追加して、ユーザーまたはコンピューター固有の構成が適用されないようにすることをお勧めします。 設定の適用方法について詳しくは、こちらをご覧ください

例えば次が挙げられます。

<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
  </packageSources>
  <packageSourceMapping>
    <clear />
  </packageSourceMapping>
</configuration>

Tip

組織がapi.nuget.orgへのアクセスをブロックする場合は、ネットワーク管理者にhttps://data.nuget.org/v3/index.jsonを許可し、NuGet Audit監査ソースとして構成することを検討してください。 このエンドポイントは、パッケージではなく脆弱性データのみを提供するため、 api.nuget.org がブロックされている場合でも許可される可能性があります。

NuGet フィード

📦 パッケージ消費者

信頼できるパッケージ ソースを使用します。 パブリックとプライベートの複数の NuGet ソース フィードを使用している場合は、任意のフィードからパッケージをダウンロードできます。 依存関係かく乱などの既知の攻撃をビルドで予測してセキュリティ保護できるようにするには、パッケージの取得元である特定のフィードを把握するのがベスト プラクティスです。 アップストリーミング機能を備えた単一のフィードまたはプライベートフィードを使用して保護できます。

パブリック ソースとプライベート ソースの両方を構成すると、パッケージ メタデータ ( dotnet package adddotnet list package --outdated/--deprecated/--vulnerableなど) を照会するクライアント コマンドは、要求されたパッケージ ID を、パブリック ソースを含むすべての構成済みソースに送信します。 パッケージ ソース マッピング は、復元、インストール、更新中に NuGet がパッケージをダウンロードする場合にのみ適用されるため、これを防ぐわけではありません。 これらの機能のギャップの現在の状態については、次の追跡の問題を参照してください。

パッケージ フィードのセキュリティ保護の詳細については、「プライベート パッケージ フィードを使用するときにリスクを軽減する 3 つの方法」を参照してください。

プライベート フィードを使用する場合は、資格情報管理に関するセキュリティ ベスト プラクティスを参照してください。

クライアント信頼ポリシー

📦 パッケージ消費者

使用するパッケージで署名が必要なポリシーをオプトインすることができます。 これにより、作成者によって署名されている場合に限りパッケージの作成者を信頼したり、NuGet.org によって署名されたリポジトリである特定のユーザーまたはアカウントによって所有されている場合にパッケージを信頼したりすることができます。

クライアント信頼ポリシーを構成するには、こちらのドキュメントを参照してください

ロック ファイル

📦 パッケージ消費者

ロック ファイルには、パッケージのコンテンツ ハッシュが格納されます。 インストールしようとするパッケージのコンテンツ ハッシュがロック ファイルと一致する場合は、パッケージの再現性が保証されます。

ロック ファイルを有効にするには、こちらのドキュメントを参照してください

パッケージ ソース マッピング

📦 パッケージ消費者

パッケージ ソース マッピングを使用すると、ソリューション内の各パッケージがどのソースから復元されるかを nuget.config ファイルで一元的に宣言できます。

パッケージ ソース マッピングは、現在、NuGet が復元、インストール、更新中にパッケージをダウンロードする場合にのみ適用されます。 現在の制限は、他のクライアント コマンドがパッケージ メタデータを照会するソースをまだフィルター処理していない点です。 詳細については、「 NuGet フィード」を参照してください。

パッケージ ソース マッピングを有効にするには、次のドキュメントを参照してください

コンピュータのセキュリティ保護

ディレクトリのアクセス許可

📦 パッケージ消費者

Windows、Mac および一部の Linux ディストリビューションでは、ユーザー アカウントのホーム ディレクトリは既定でプライベートです。 ただし、一部の Linux ディストリビューションでは、既定で同じコンピューター上の他のアカウントでユーザー ディレクトリを読み取り可能にします。 さらに、NuGet のグローバル パッケージ フォルダーや HTTP キャッシュを既定以外の場所にリダイレクトするための複数の構成オプションがあります。 ソリューション、プロジェクト、リポジトリは、ユーザーのホーム ディレクトリの外部でも作成される場合があります。

nuget.org 上にないパッケージを使用している場合、コンピューター上の他のアカウントが NuGet のグローバル パッケージ、HTTP キャッシュ ディレクトリ、またはプロジェクトのビルド出力ディレクトリを読み取ることができる場合、これらのパッケージは、それらのパッケージへのアクセス許可を持たないユーザーに公開される可能性があります。

Linux では、dotnet nuget update source を使用して nuget.config ファイルのアクセス許可が変更され、ファイル所有者のみが読み取り可能になります。 ただし、nuget.config ファイルを他の方法で編集し、ファイルが他のアカウントがファイルを読み取ることができる場所にある場合は、パッケージ ソース URL またはパッケージ ソースの資格情報に関する情報漏えいが発生する可能性があります。 同じコンピューターの他のユーザーが nuget.config ファイルを読み取ることができないことを確認する必要があります。

ダウンロード ディレクトリ内のソリューション

📦 パッケージ消費者

ダウンロード ディレクトリ内のソリューションまたはプロジェクトで作業する場合は、特別な注意を払う必要があります。 NuGet は複数の構成ファイルから設定を集約し、MSBuild は通常、Directory.Build.props、Directory.NuGet.props、Directory.Build.targets を任意の親ディレクトリ内からファイルシステムのルートまでインポートします。他のファイルを含むこともあります。

ダウンロード フォルダーは、通常、Web ブラウザーがインターネットからファイルをダウンロードする既定の場所であるため、追加のリスクがあります

ビルド エージェント

📦 パッケージ消費者

毎ビルド後に初期状態にリセットされないビルド エージェント (CI エージェント) には、考慮する必要がある複数のリスクがあります。

資格情報を安全に管理する方法については、認証済みフィードからのパッケージ利用に関するドキュメントを参照してください。

NuGet がデータを格納するディレクトリを変更する方法については、「グローバル パッケージ、キャッシュ、一時フォルダーを管理するためのドキュメント」を参照してください。 これらのディレクトリは、毎ビルド後に CI エージェントがクリーン アップするディレクトリに構成する必要があります。

プロジェクトで使用されるパッケージは、プロジェクトのビルド出力ディレクトリに残っている可能性があることに注意してください。 認証されたソースのパッケージをプロジェクトで使用している場合、同じ CI エージェントの他のユーザーがパッケージ アセンブリに不正アクセスする可能性があります。 そのため、ビルドが失敗したり取り消されたりした場合でも、ビルドの最後にリポジトリをクリーンアップする必要があります。

サプライ チェーンを監視する

GitHub シークレット スキャン

📦🖊パッケージ作成者

誤ってコミットされたシークレットが不正に使用されるのを防ぐため、GitHub によりリポジトリで NuGet API キーがスキャンされます。

シークレット スキャンについて詳しく知りたい方は、シークレット スキャンについてを参照してください。

作成者によるパッケージへの署名

📦🖊パッケージ作成者

作成者署名を使用すると、パッケージの作成者がパッケージに自身の身元を証明し、消費者がそのパッケージがあなたからのものであることを確認することができます。 これにより、内容の改ざんから保護され、パッケージの提供元とパッケージの信頼性に関する単一の正しい情報源として機能します。 クライアント信頼ポリシーと組み合わせると、パッケージが特定の作成者からのものであることを確認できます。

作成者によるパッケージへの署名については、パッケージへの署名に関するページを参照してください。

再現可能なビルド

📦🖊パッケージ作成者

再現可能なビルドを使うと、ビルドするたびにバイト単位で同一のバイナリを作成できます。また、ソース コードのリンクとコンパイラのメタデータを含むので、パッケージ コンシューマーがバイナリを直接再作成し、ビルド環境が侵害されていないことを検証することができます。

再現可能なビルドの詳細については、「ソース リンクを使ったパッケージの作成」と「再現可能なビルドの検証」の仕様を参照してください。

2 要素認証 (2FA)

📦🖊パッケージ作成者

nuget.org のすべてのアカウントで 2FA が有効になっています。 これにより、GitHub アカウントや NuGet.org アカウントにログインするときに、追加のセキュリティレイヤーが適用されます。

パッケージ ID プレフィックスの予約

📦🖊パッケージ作成者

パッケージ ID プレフィックスが指定した条件を満たしている場合、対応する名前空間でパッケージ ID プレフィックスを予約し、それに一致する所有者を関連付けることによって、パッケージの ID を保護できます。

ID プレフィックスの予約の詳細については、「パッケージ ID プレフィックスの予約」を参照してください。

脆弱なパッケージの非推奨化と一覧からの削除

📦🖊パッケージ作成者

作成したパッケージに脆弱性があることがわかっている場合に .NET パッケージ エコシステムを保護するには、パッケージを非推奨にして一覧から削除し、パッケージを検索するユーザーに表示されないようにすることをお勧めします。 非推奨で一覧にないパッケージを使用している場合は、パッケージの使用を避ける必要があります。

パッケージを非推奨にし、一覧から削除する方法については、パッケージの非推奨と一覧からの削除に関するドキュメントを参照してください。

また、既知の情報を GitHub アドバイザリ データベースに報告することも検討してください。

まとめ

ソフトウェア サプライ チェーンは、コードに組み込まれたり影響したりするすべてのものです。 サプライ チェーンの侵害は現実であり、一般に広がりつつありますが、それでもまだまれです。そのため、実施できる最も重要なことは、依存関係を把握し、依存関係を管理し、サプライ チェーンを監視することにより、サプライ チェーンを保護することです。

あなたは、NuGet および GitHub が提供する、サプライチェーンをより効果的に表示、管理、監視するためのさまざまな方法について学習しました。

世界中のソフトウェアのセキュリティ保護の詳細については、The State of the Octoverse 2020 のセキュリティ レポートに関するページを参照してください。