GitHubの依存関係グラフ~ 開発ワークフロー全体をセキュアに

Image of Maya Kaczorowski

よりセキュアなコードのリリースは、開発者を中心に考え、開発の初期段階からセキュリティの問題を解決するワークフローが重要です。本ブログでは、ワークフローのすべてのステップでセキュリティを組み込む方法について検討します。GitHubの依存関係グラフを支えているものについて、GitHubのサプライチェーンセキュリティ製品管理者であるMaya Kaczorowskiが詳しく説明します。

オープンソースの利用が加速する中で、プロジェクトにはおそらく何百もの依存関係が存在します。平均でリポジトリあたり203個のパッケージ依存関係が存在することがわかっています。アプリケーションにどのような依存関係があるのか、どうすれば実際に判断することができるのでしょうか。ドキュメントまたはStack Overflowからコードを自分のコードにコピペしすることも、依存関係と言えるでしょう。

依存関係とは何か、また、GitHubの依存関係グラフでコードどのような影響があるかを確認する方法について、そして依存関係を安全に維持するために何をすべきかについて、詳しく見ていきましょう。

依存関係の把握

依存関係はソフトウェアの実行に必要なバイナリです。これには、アプリケーション開発時に必要なバイナリ(多くの場合、開発依存関係と呼ばれる)と、実行時にアプリケーションの一部として実際に使用されるバイナリの両方が含まれていると考えることができます。また、スタックの他の部分にも依存関係があります。たとえば、アプリケーションがオペレーティングシステム上で実行される、などです。ただし、ここでは分かりやすくするために、これについては除外します。

依存関係は、開発者がアプリケーションの一部として指定したときに環境に取り込まれます。これは通常、依存関係が宣言されるマニフェストファイル、または特定バージョンの依存関係が指定されるロックファイルの一部として実行されます。依存関係は推移的に含まれる場合もあります。つまり、特定の依存関係を指定していなくても、自分で指定した依存関係によって指定されている場合、結果的にその依存関係に依存することになります。

これが、ネットワーク効果を介して依存関係が急速に拡大する仕組みであり、アプリケーションが何に依存しているかを識別することが難しくなる理由ともなります。これを簡単に把握できるようにする一般的な方法は、依存関係を非巡回グラフとして提示し、レビューすることです。つまり、あるバイナリから別のバイナリへの依存の方向を示すことによって、一連の依存関係を表示します。ファミリーツリーと同様に、アプリケーションには直接引き込む依存関係があり(ファミリーツリーにおけるペアレントのようなもの)、その依存関係にも独自の依存関係(ペアレント関係の上位のようなもの)があります。ただし、類似しているのはそこまでです。複数の項目がすべて1つのバイナリにつながる可能性があり、また所有する依存関係の数に制限はありません。おそらく、”ペアレント関係のさらに上位の関係”よりもさらに前に遡ることができます。

依存関係を詳しく把握する必要がある理由は、主にセキュリティとコンプライアンスの2つです。セキュリティの観点からは、コード内に潜む脆弱性を検出する必要があります。これには、依存関係に含まれる可能性があるアプリケーションのセキュリティ脆弱性が含まれます。コンプライアンスの観点からは、依存関係でどのようなライセンスが使用されているか、および、その依存関係の使用に対する制限を知っておく必要があります。

GitHubの依存関係グラフで依存関係を発見する方法

GitHubの依存関係グラフは、リポジトリまたはパッケージにおけるすべての上流の依存関係と、パブリックな下流の依存関係を識別します。プロジェクトの依存関係と、脆弱性情報などの一部のプロパティを確認できます。

依存関係グラフを生成するために、GitHubはリポジトリの明示的に宣言された、マニフェストまたはロックファイルで指定されている依存関係を調べます。これは、各エコシステムにとって、npmの`package.json`など、標準的な形式です。有効になっている場合、依存関係グラフはリポジトリ内の既知のパッケージマニフェストファイルをすべて自動解析し、これを使用して既知の依存関係名とバージョンでグラフを作成します。GitHubは何百万ものリポジトリに対してこれを実行します。これらのパッケージの多くはGitHub上でコードをホストしているため、どのリポジトリがどのパッケージを生成するか推測できます。新しい依存関係を追加すると、つまりマニフェストファイルを変える変更をリポジトリのデフォルトブランチにプッシュすると、項目が依存関係グラフに追加されます。

依存関係グラフには直接的な依存関係に関する情報が含まれているだけでなく、推移的な依存関係も含まれています。ロックファイルの一部として指定されている依存関係については(バージョンを含む)、その情報が使用されます。指定されていない場合は、依存関係の依存関係から推測されます(バージョンは除く)。

マニフェストファイルを解析するこの手法を使用することで、GitHubの依存関係グラフは他とは少し異なる方法で作成されます。他の手法では、レジストリにチェックインされた後に行う完成されたアーティファクトの調査、またはビルドプロセスの一部として引き込まれた依存関係の検出が含まれます。完璧なソリューションは存在しないため、これらの手法ではすべて、不正確な依存関係の検出につながります。パイプラインの複数の段階で依存関係をレビューし、予期せず含まれている依存関係を識別できれば理想的です。GitHubの依存関係グラフは、開発プロセスの早期にコード内の依存関係を検出するため、使用するビルドパイプラインに依存せず、また追加構成を行うことなく依存関係を検出できます。

依存関係グラフは、パブリックリポジトリではデフォルトで有効化されており、また読み取り専用アクセスを付与することでプライベートリポジトリでも有効化できます。パブリックパッケージの場合、パッケージの下流のパブリック依存関係を表示することもできます。プライベートリポジトリの依存関係グラフを有効にした場合、依存関係の所有者にはあなたがパッケージを使用していることは表示されません。可視性は一方向のみです。

依存関係の維持

依存関係を健全な状態で維持するために、いくつかの手順が必要です。まずは、依存関係がどのようなものか把握し、アプリケーションの一部として明示的に指定することです。依存関係をリポジトリにベンダリングするのではなく、マニフェストファイルに指定することで、特定のサードパーティの依存関係を参照していることがわかります。これにより、再コピーせずに依存関係をアップグレードできるため、より新しい機能に簡単に適応できるようになります。開発チームにかかる保守の負担も軽減されます。

エコシステムが対応していて依存関係を検証する特定のプロセスに従う必要がある場合、または、さらなる確信を得たい場合は、ロックファイルも指定します。これにより、たとえ推移的な依存関係であっても、明示的な選択なしに新しいバージョンを引き込むことがなくなり、開発およびビルド環境全体で必ず一貫性のあるバージョンを使用することができます。可能性のあるバージョンを広範囲に許可できるマニフェストファイルと比べて、ロックファイルでは直接的および推移的な依存関係の両方で具体的なバージョンを指定する必要があります。

マニフェストとロックファイルのどちらも、最新バージョンの依存関係を取り込むためにレビューとアップデートを定期的に行ってください。これは、新たに発見された脆弱性が依存関係に含まれている場合に特に重要です。GitHubでは、Dependabotのセキュリティ脆弱性アラートが新しい脆弱性を通知し、Dependabotセキュリティアップデートを使用してその脆弱性に対処します。脆弱性が存在しない場合であっても、アップグレードが重要になった時に簡単に実行できるように、Dependabotバージョンアップデートで新しいリリースを定期的にチェックしてください。

最後に、これが実際には最も困難ですが、不要な依存関係を削除してください。依存関係の数が少なければ、セキュリティとコンプライアンスのリスクも小さくなります。アプリケーション内で使用していないものにパッチを適用したり、保守作業を行う必要はありません。

ここまでで、依存関係とそれらを維持するためにすべきことを見てきました。次回のブログでは、依存関係グラフの使用を開始して、アプリケーションで使用される依存関係をリポジトリレベルで表示する点について説明します。

安全なソフトウェア開発のために

より簡単な方法でコードを安全に維持したい場合は、このシリーズの今後の投稿にご注目ください。または、セキュリティに関する当社のホワイトペーパーをご確認ください

GitHubでは、企業における安全なソフトウェア開発を進めるためのソリューションを提供しています。ご相談がある場合は、GitHub営業担当にお問い合わせください。