開発者ツール · SHA ハッシュ計算ツール
コンテンツ アドレッシング: Git、Docker、npm が SHA ダイジェストを名前として使用する方法
· 背景
しゃ-256 ドッカー 暗号化 開発者ワークフロー
Git コミット、コンテナー イメージ ダイジェスト、およびロックファイル整合性文字列はすべて同じ考え方であり、ハッシュによってデータに名前を付けるというものです。この投稿では、コンテンツ アドレッシングと、そこから各エコシステムが得られるものについて説明します。
Docker プル内の sha256: その文字列とは何か、また同じイメージに対して文字列が変更されない理由
バージョン管理システム、コンテナー ランタイム、およびパッケージ マネージャーはすべて同じ命名方法を使用します。つまり、ファイルまたはバイトのコレクションは SHA ダイジェストによって名前が付けられます。 Git では、コミットの 40 文字 SHA-1 識別子 (または最新のリポジトリでは 64 文字 SHA-256) は、コミットのコンテンツ (ツリー、作成者、タイムスタンプ、メッセージ) から計算されます。 1 バイトを変更すると、SHA が変更されます。 Docker では、各レイヤー ダイジェストはレイヤーのコンテンツの SHA-256 ハッシュであり、イメージ ダイジェストはマニフェストから計算されます。 npm およびその他のパッケージ マネージャーでは、整合性フィールドには、ダウンロードを検証するために tarball の SHA-512 ダイジェストが保存されます。コンテンツ アドレッシングとは、名前が中央データベースやタイムスタンプではなく、バイトのみに依存することを意味します。
利点は、各システム内で不変であることです。 git commit SHA-256:abc... は、ハッシュによって ID が決定されるため、常に同じツリーとメッセージを参照します。誰かが同じ SHA で異なるコミットを持っていると主張する場合、同じバイトが 2 つの異なるハッシュを生成し、暗号化が破壊されると主張していることになります。重複排除は自動的になります。同一のバイトを持つ 2 つのファイルは同じダイジェストを生成するため、ストレージ システムはバイトを 1 回保存して 2 回参照できます。整合性チェックは、ダイジェストを再計算して比較するだけで簡単になります。転送中または保存中にバイトが変更された場合、ダイジェストは一致しなくなります。
ハッシュによるデータの名前付け — コンテンツ アドレス指定のアイデアと、それによって重複排除と整合性が無料になる理由
Git は、SHA ダイジェストをキーとしたオブジェクト (コミット、ツリー、BLOB、タグ) を保存します。 `git cat-file` コマンドはオブジェクト ID を取得し、バイトを取得します。オブジェクト ストアはコンテンツ アドレス指定されます。要求は場所や名前ではなく、ダイジェストによって行われます。リポジトリのクローンを作成すると、git は各オブジェクトのダイジェストを再計算し、転送にパックされたダイジェストと照合することで各オブジェクトを検証します。 SHA-1 から SHA-256 への移行は段階的に行われます。リポジトリは互換性のために両方をサポートできます。ディスク上のフォーマットには、オブジェクトのタイプ、サイズ、圧縮バイトが保存されます。ダイジェストは、正規の非圧縮形式で計算されます。
最新の Git リポジトリは SHA-256 を使用できます。SHA-1 の衝突が実用化されたため、移行が進行中です (2017 で実証され、2020 で改良されました)。 SHA-256 を使用するリポジトリ内のコミットには、40 ではなく、64 文字の 16 進識別子が含まれます。 `git hash-object` コマンドは、BLOB (ファイルの内容) を保存せずに SHA を計算します。 `git commit-tree` は、ツリー構造とメッセージの SHA を計算します。どちらの操作も決定的です。同じバイトからは常に同じダイジェストが生成されます。これは、GitHub や他のフォージが一貫してコミット SHA を表示できる方法です。作成者のクローンが計算したのと同じダイジェストを計算します。
Git はコンテンツ アドレス指定されたオブジェクトを使用し、このツールはテキスト ダイジェストを再現できます。移行の詳細には Git 固有のソースが必要です
Docker イメージはレイヤーで構築されており、各レイヤーはファイル システム デルタ (前のレイヤーからの変更) です。 OCI イメージ仕様は、レイヤーのダイジェストとイメージ マニフェストのダイジェストを計算する方法を定義します。レイヤ ダイジェストは、レイヤ ファイルを含む圧縮 tar ファイルの SHA-256 です。マニフェストは、レイヤー、そのダイジェスト、メタデータをリストした JSON ドキュメントです。イメージ ダイジェストは、マニフェスト JSON 自体の SHA-256 です。 `latest` のようなタグを使用してイメージをプルすると、レジストリはタグを検索し、マニフェスト ダイジェストを返します。その後、ダイジェストによって直接プルすることができ、毎回まったく同じバイト (すべてのレイヤーとメタデータ) を確実に取得できます。
ローカル イメージ上の `docker inspect` コマンドは、そのダイジェストを表示します。 2 台のマシンで同じタグから同じイメージを実行すると、同じマニフェストを指すタグがレジストリにまだ保持されている場合、同じダイジェストが生成されます。コンテンツ アドレッシングにより、イメージ サプライ チェーンが監査可能になります。CI/CD パイプラインは、デプロイしたイメージがビルド ログ内のダイジェストと一致することを検証でき、セキュリティ スキャナーは、移動する可能性があるタグではなくダイジェストによって、特定の脆弱性を持つことがわかっているすべてのイメージをレポートできます。
コンテナ — OCI マニフェストとレイヤー ダイジェスト、およびタグは移動できるがダイジェストは移動できない理由
パッケージ マネージャーは、ダイジェストを使用して、ダウンロードの改ざんや破損を検証します。 npm の `package-lock.json` ファイルには、依存関係ごとに `integrity` フィールドが含まれており、ハッシュ (通常は SHA-512) とエンコーディング (通常は Base64) が含まれます。 npm は tarball をダウンロードするときに、ハッシュを再計算して比較します。ハッシュが一致しない場合、インストールは失敗します。 Go は、モジュール パス、バージョン、モジュール ソースの SHA-256 という同様の構造を持つ `go.sum` ファイルを使用します。 Cargo は `Cargo.lock` のチェックサムを使用します。原理は同じです。依存関係が最初に解決されるときにダイジェストが 1 回計算され、その後のインストールごとにチェックされます。
整合性チェックでは、パッケージを署名機関にアップロードしたり、署名を個別に保存したりする必要はありません。ダイジェストは整合性チェックです。最大限の保証を得るために、プロジェクトは Go プロジェクトの透過性システムによって署名された `go.sum` を使用するか、他の検証と組み合わせた npm 整合性を使用しますが、基本的なケースは単純です。パブリッシャーはダイジェストを 1 回計算し、それをロックファイルに記録し、コンシューマ側のツールはダウンロードされたバイトが一致することを検証します。
パッケージの整合性エンコーディングはさまざまです。この計算機でサポートされている SHA 出力のみがここでアサートされます
同じアルゴリズムを介した同じバイトは、バイトの出所に関係なく、常に同じダイジェストを生成します。開発者のコミットのローカル ビルドは、同じリポジトリから同じリビジョンをチェックアウトする CI/CD システムと同じ SHA-256 を生成します。この再現性がコンテンツ アドレス指定の機能の理由です。配信メカニズムを信頼せずにアーティファクトを検証できます。ダイジェストは暗号化されたコミットメントになります。1 バイトでも変更するとダイジェストが無効になります。
ダイジェストを個別に (アーティファクトを配布する前に) 配布すると、実行中の変更を防ぐことができます。リリース前に公開された Web ページには「expect SHA-256:abc...」と表示され、ユーザーはそれに対してダウンロードを検証できます。パブリック リポジトリで公開された git コミットは、バイトに対するコミットメントです。ダイジェストがそれを証明しています。
実用的な例 — バイトから 1 つの BLOB をたどって、ツールが使用する名前にダイジェストします
システムが異なれば、ダイジェストのエンコード方法も異なります。 Git はデフォルトで小文字の 16 進数 (40 または 64 の 16 進文字) を使用します。 Docker は、`sha256:` の後に 16 進数が続く形式を使用します。 npm と Go は整合性フィールドで Base64 を使用します。バイトは同じです。表現が異なるだけです。 「abc」の SHA-256 ダイジェストは常に同じ 256 ビットですが、64 文字の 16 進文字列、44 文字の Base64 文字列、またはそのいずれかが後に続く `sha256:` のようなラベルとして表示される場合があります。エンコーディング間の変換はロスレスです。ダイジェストはどの表現でも同じ値です。
ツール間でダイジェストを比較する場合、エンコーディングを理解することが重要です。 Git が 16 進ダイジェストを出力し、ツールが Base64 を表示する場合は、一方の表現をもう一方の表現に変換して、それらが一致することを確認する必要があります。 ToolAcre の SHA ハッシュ計算ツールは、すべてのダイジェストに対して 16 進数と Base64 の両方を表示するため、変換や他のシステムとの相互参照が容易になります。
これでカバーされないもの — 各ツールが使用する特定のエンコード (hex と Base64) については、別の投稿で説明します。
コンテンツ アドレス指定は暗号化に固有のものではありませんが、暗号化ハッシュによって安全になります。 CRC32 チェックサムもデータのコンテンツアドレスを指定しますが、CRC32 の衝突は一般的であり、衝突が起こる可能性があります。このリポジトリは SHA-256 を破損としてマークしませんが、CRC32 は敵対的な整合性プリミティブとして提供されていません。ハッシュ アルゴリズムの選択はセキュリティにとって重要です。SHA-256 は、敵対者に対する整合性保護を必要とするシステムの最新の標準です。 SHA-1 はレガシーのみです (Git などは移行中です)。適切なアルゴリズムを選択することは、命名スキームとしてコンテンツ アドレッシングを選択することとは別の決定です。
暗号化ハッシュと組み合わせたコンテンツ アドレッシングは、最新のソフトウェアにおけるサプライ チェーンの整合性の基盤です。インストールするすべてのパッケージ、実行するすべてのコンテナ、およびチェックアウトするすべてのコミットは、安全な転送に依存せずに、元の発行者が意図したバイトであることを検証できます (ただし、安全な転送は依然として推奨事項です)。
要点: ハッシュは ID です。ToolAcre SHA ハッシュ計算ツールを使用すると、これらのシステムが依存しているのと同じダイジェストを計算できます。
コンテンツのアドレス指定は、エンコード、保存場所、転送メカニズムとは独立しています。同じバイトは、ローカル、CDN、レジストリに保存されるか、HTTP またはセキュア HTTPS 経由で送信されるかに関係なく、同じダイジェストを生成します。ダイジェストはバイトに対する暗号化コミットメントであり、その検証には外部サービスではなく、バイトとアルゴリズムのみが必要です。これが、コンテンツ アドレッシングによってオフライン検証が可能になる理由です。信頼できないチャネル経由でファイルをダウンロードし、ダイジェストをチェックして、バイトが本物かどうかを知ることができます。
ToolAcre SHA ハッシュ計算ツールを使用すると、これらのシステムが依存するものと同じダイジェストを計算できます。文字列を貼り付けるかファイルを監視し、計算機を実行すると、Docker、Git、npm、その他のツールが内部で使用する SHA-256、SHA-384、SHA-512 のダイジェストが表示されます。計算されたダイジェストを元のソースのダイジェストと比較して、バイトが変更されていないことを確認します。電卓は、貼り付けた UTF-8 テキストをハッシュします。ファイルやキーマテリアルをハッシュしないため、ハッシュできるもの (テキスト入力) とハッシュできないもの (バイナリファイル、エンコードされた形式の暗号キー) の境界は明確で文書化されています。