これはおそらく現実の世界では決して起こらなかったし、決して起こらないかもしれませんが、これを考えてみましょう:gitリポジトリがあり、コミットを行い、非常に不運になったとします:ブロブの1つが同じSHA-1を取得するすでにリポジトリにある別のものとして。問題は、Gitがこれをどのように処理するかということです。単に失敗しますか?2つのblobをリンクして、コンテキストに応じてどちらが必要かを確認する方法を見つけますか?
実際の問題よりも頭の痛いですが、問題は興味深いものでした。
これはおそらく現実の世界では決して起こらなかったし、決して起こらないかもしれませんが、これを考えてみましょう:gitリポジトリがあり、コミットを行い、非常に不運になったとします:ブロブの1つが同じSHA-1を取得するすでにリポジトリにある別のものとして。問題は、Gitがこれをどのように処理するかということです。単に失敗しますか?2つのblobをリンクして、コンテキストに応じてどちらが必要かを確認する方法を見つけますか?
実際の問題よりも頭の痛いですが、問題は興味深いものでした。
回答:
この場合のGitの動作を正確に調べるために実験を行いました。これはバージョン2.7.9〜rc0 + next.20151210(Debianバージョン)に対応しています。基本的に、次のdiffを適用してgitを再構築することで、ハッシュサイズを160ビットから4ビットに減らしました。
--- git-2.7.0~rc0+next.20151210.orig/block-sha1/sha1.c
+++ git-2.7.0~rc0+next.20151210/block-sha1/sha1.c
@@ -246,6 +246,8 @@ void blk_SHA1_Final(unsigned char hashou
blk_SHA1_Update(ctx, padlen, 8);
/* Output hash */
- for (i = 0; i < 5; i++)
- put_be32(hashout + i * 4, ctx->H[i]);
+ for (i = 0; i < 1; i++)
+ put_be32(hashout + i * 4, (ctx->H[i] & 0xf000000));
+ for (i = 1; i < 5; i++)
+ put_be32(hashout + i * 4, 0);
}
それから私はいくつかのコミットを行い、次のことに気づきました。
#2の場合、通常「git push」を実行すると次のようなエラーが発生します。
error: object 0400000000000000000000000000000000000000 is a tree, not a blob
fatal: bad blob object
error: failed to push some refs to origin
または:
error: unable to read sha1 file of file.txt (0400000000000000000000000000000000000000)
ファイルを削除してから「git checkout file.txt」を実行した場合。
#4と#6の場合、通常は次のようなエラーが発生します。
error: Trying to write non-commit object
f000000000000000000000000000000000000000 to branch refs/heads/master
fatal: cannot update HEAD ref
「git commit」を実行するとき。この場合、新しいハッシュが作成されるため(タイムスタンプが変更されているため)、通常はもう一度「git commit」と入力します。
#5と#9の場合、通常は次のようなエラーが発生します。
fatal: 1000000000000000000000000000000000000000 is not a valid 'tree' object
「git commit」を実行するとき
誰かが破損したリポジトリのクローンを作成しようとすると、通常、次のようなものが表示されます。
git clone (one repo with collided blob,
d000000000000000000000000000000000000000 is commit,
f000000000000000000000000000000000000000 is tree)
Cloning into 'clonedversion'...
done.
error: unable to read sha1 file of s (d000000000000000000000000000000000000000)
error: unable to read sha1 file of tullebukk
(f000000000000000000000000000000000000000)
fatal: unable to checkout working tree
warning: Clone succeeded, but checkout failed.
You can inspect what was checked out with 'git status'
and retry the checkout with 'git checkout -f HEAD'
私が「心配」しているのは、2つのケース(2、3)で警告なしにリポジトリが破損し、3つのケース(1、7、8)ですべてが問題ないように見えるが、リポジトリの内容が予想と異なることです。することが。クローンまたはプルする人々は、あなたが持っているものとは異なるコンテンツを持っています。エラーで停止するため、ケース4、5、6、9は問題ありません。少なくともすべてのケースでエラーで失敗した方がいいと思います。
元の回答(2012)(下記のshattered.io
2017 SHA1衝突を参照)
Linusからのその古い(2006年の)回答はまだ関連があるかもしれません:
いいえ。同じSHA1を持つ場合、相手からオブジェクトを受け取ったときに、すでに持っているオブジェクトを上書きしないことを意味します。
つまり、衝突が発生すると、特定のリポジトリ内の「以前の」オブジェクトが常に上書きされることになります。ただし、gitオブジェクトネットワークが完全に順序付けされていないDAGを生成するという意味で、「以前」は明らかにリポジトリごとであることに注意してください。したがって、直接の祖先の場合、異なるリポジトリは「以前」が何であるかについて合意します。オブジェクトは、直接関係のない別々のブランチを経由して渡されたため、2つの異なるリポジトリが2つのオブジェクトを異なる順序で取得した可能性があります。
ただし、「以前のバージョンは上書きされます」は、セキュリティの観点からは非常に重要です。gitモデルでは、主に 自分のリポジトリ。
したがって、「git pull
」を実行すると、新しい着信オブジェクトは、定義上、既存のオブジェクトよりも信頼性が低くなるため、新しいオブジェクトが古いオブジェクトを置き換えることを許可するのは間違っています。したがって、衝突の2つのケースがあります。
あなたがどういうわけか非常に不運であり、2つのファイルが同じSHA1を持つことになる不注意な種類。
その時点で何が起きるかは、そのファイルをコミットする(または "git-update-index
"を実行してインデックスに移動するが、まだコミットされていない)場合、新しいコンテンツのSHA1が計算されますが、古いオブジェクトと一致するため、新しいオブジェクトは作成されず、commit-or-indexは、オブジェクトをます。 (インデックスが古いオブジェクトSHA1と一致するため、「」のようなものがチェックアウトされたコピーを使用することを意味するため)すぐには気づきませんが、ツリーレベルの差分を行う(またはクローンを行う)場合またはプルするか、強制的にチェックアウトします)そのファイルが何かに変わったことに突然気付くでしょう期待したものとはまったく異なる古いオブジェクトを指し示すことになります。 そのため、この種の衝突にかなり早く気付くでしょう。 関連ニュースでは、問題は偶発的な衝突についてどうするかです。 最初に、偶発的な種類の衝突が本当に本当に本当にあることを人々に思い出させてくださいgit diff
ありそうもないので、宇宙の完全な歴史の中でそれを見ることは決してないでしょう。
しかし、もしそれが起こったとしても、それは世界の終わりではありません。ほとんどの場合、わずかに衝突したファイルを変更し、変更した内容で新しいコミットを強制するだけです(「/* This line added to avoid collision */
」というコメントを追加)。次に、危険であることが示されている魔法のSHA1についてgitに教えます。
したがって、数百万年以上の間、おそらく1つまたは2つの「毒された」SHA1値をgitに追加する必要があります。メンテナンスの問題になることはほとんどありません;)衝突の攻撃の種類は、誰かが(またはブルート強制)SHA1を破ったため。
この1は明らかである多くの可能性が高い不注意種類以上が、定義によってそれは常に「リモート」のリポジトリです。攻撃者がローカルリポジトリにアクセスできる場合、攻撃者はあなたをだますためのはるかに簡単な方法を持っているでしょう。
したがって、この場合、衝突は完全に問題ではありません。攻撃者が意図したものとは異なる「不良」リポジトリを取得しますが、実際には彼の衝突オブジェクトを使用することはないので文字通り、攻撃者は衝突をまったく発見しなかった、しかし、すでに持っているオブジェクトを使用するだけです(つまり、同じSHA1を生成する同一ファイルの「些細な」衝突と100%同等です)。
SHA-256を使用しての質問は、定期的に言及したが、今(2012年)のために作用されていません。
注:2018およびGit 2.19以降、コードはSHA-256を使用するようにリファクタリングされています。
注(ユーモア):特定のSHA1 プレフィックスへのコミットを強制できます。BradFitzpatrick(bradfitz
)のプロジェクトgitbruteを使用します。
gitbruteは、作成者+コミッターのタイムスタンプのペアをブルートフォースして、結果のgitコミットに希望のプレフィックスが付けられるようにします。
例:https : //github.com/bradfitz/deadbeef
Daniel Dinnyes は、7.1 Git Tools-Revision Selectionへのコメントで指摘しています。
同じ夜に関係のない事件で、プログラミングチームのすべてのメンバーがオオカミに攻撃されて殺される可能性が高くなります。
さらに最近(2017年2月)shattered.io
は、SHA1衝突を偽造する可能性を示しました
(Linus TorvaldsのGoogle+の投稿を含む、別の回答で詳細を参照してください)。
詳細については、Valerie Anita Auroraの「暗号ハッシュ関数の寿命」を参照してください。
そのページで、彼女は次のように述べています。
Googleは6500 CPU年と110 GPU年を費やして、セキュリティが重要なアプリケーションでSHA-1の使用をやめる必要があるすべての人を説得しました。
それもかっこいいから
詳細については、以下の個別の回答をご覧ください。
/* This line added to avoid collision */
:Dあなたは2回宝くじに勝つことができます:P
/* This line added to avoid collision of the avoid collision line */
Pro Gitによると:
リポジトリ内の前のオブジェクトと同じSHA-1値にハッシュするオブジェクトをたまたまコミットした場合、Gitは前のオブジェクトをGitデータベースに既に表示し、すでに書き込まれていると想定します。ある時点でそのオブジェクトを再度チェックアウトしようとすると、常に最初のオブジェクトのデータが取得されます。
したがって、失敗することはありませんが、新しいオブジェクトも保存されません。
コマンドラインでそれがどのように表示されるかはわかりませんが、それは確かに混乱を招きます。
少し下に、同じ参照がそのような衝突の可能性を説明しようとします:
以下は、SHA-1衝突が発生するために必要なことを理解するための例です。地球上の65億人すべてがプログラミングを行っており、1秒ごとにLinuxカーネルの履歴全体(100万Gitオブジェクト)に相当するコードを生成し、それを1つの巨大なGitリポジトリにプッシュすると、5年かかります。そのリポジトリには、単一のSHA-1オブジェクトの衝突の50%の確率を持つ十分なオブジェクトが含まれていました。同じ夜に関係のない事件で、プログラミングチームのすべてのメンバーがオオカミに攻撃されて殺される可能性が高くなります。
2012年からの私の以前の回答に加えて、shattered.ioとの実際のSHA-1衝突の例がここにあります(2017年2月、5年後)。ここでは、2つの衝突するPDFファイルを作成できます。つまり、SHA- 2番目のPDFファイルの有効な署名として悪用される可能性がある最初のPDFファイルの1つのデジタル署名。
「何年にもわたって死の扉が開かれ、広く使用されているSHA1機能は現在は機能しなくなっています」、およびこの図も参照してください。
2月26日更新:Linus はGoogle+の投稿で次の点を確認しました。
(1)まず、空は落ちていません。セキュリティ署名などに暗号化ハッシュを使用することと、gitなどのコンテンツアドレス可能なシステムの「コンテンツ識別子」を生成するために使用することには大きな違いがあります。
(2)第2に、この特定のSHA1攻撃の性質は、実際に軽減するのが非常に簡単であることを意味し、その軽減のために2セットのパッチが既に投稿されています。
(3)そして最後に、実際には、世界を壊さない他のハッシュへのかなり簡単な移行があります-または古いgitリポジトリですらあります。
その移行については、ハッシュアルゴリズムを表す構造を追加する2018年第1四半期のGit 2.16を参照してください。その移行の実装が開始されました。
Git 2.19(2018年第3四半期)以降、GitはSHA-256をNewHashとして選択し、コードへの統合を進めています(SHA1がデフォルト(2019年第2四半期、Git 2.21)ですが、SHA2が後継となります)。
元の回答(2月25日)しかし:
git-svn
けれども。または、ここで見られるように、svn自体で。git fsck
、今日のLinus Torvaldsが述べているように、によって簡単に検出できるデータの整合性(重複排除とエラー検出)です。git fsck
後に隠された不透明なデータを持つコミットメッセージについて警告しますNUL
(ただし、NUL
常に不正なファイルに存在するわけではありません)。transfer.fsck
にするわけではありませんが、GitHubはオンにします。オブジェクトの形式が正しくない場合やリンクが壊れている場合、プッシュは中止されます。ただし... これがデフォルトでアクティブにならない理由があります。全体のポイント SCMのは、それが1回限りのイベントについてではなく、継続的な歴史についてということです。また、基本的には、成功した攻撃は時間をかけて機能する必要があり、検出されない必要があります。
SCMを1回だましてコードを挿入し、それが来週検出された場合、実際には有用なことは何もしていません。火傷しただけです。
ジョーイ・ヘスこれらのPDFをGitリポジトリで試してみたところ、次のことがわかりました。
これには、SHAとサイズが同じ2つのファイルが含まれます。gitがヘッダーをコンテンツの前に付加する方法のおかげで、これらは異なるblobを取得します。
joey@darkstar:~/tmp/supercollider>sha1sum bad.pdf good.pdf
d00bbe65d80f6d53d5c15da7c6b4f0a655c5a86a bad.pdf
d00bbe65d80f6d53d5c15da7c6b4f0a655c5a86a good.pdf
joey@darkstar:~/tmp/supercollider>git ls-tree HEAD
100644 blob ca44e9913faf08d625346205e228e2265dd12b65 bad.pdf
100644 blob 5f90b67523865ad5b1391cb4a1c010d541c816c1 good.pdf
これらの衝突するファイルに同一のデータを追加すると他の衝突が発生しますが、データの先頭に追加すると発生しません。
だから 攻撃主な方法(コミットの偽造)は次のようになります。
- 通常のコミットオブジェクトを生成します。
- 選択した接頭辞としてコミットオブジェクト全体とNULを使用します。
- 同一プレフィックス衝突攻撃を使用して、衝突する良/悪オブジェクトを生成します。
- ...そして、これは役に立たないオブジェクトとコミットオブジェクトが同じツリーを指しているので役に立たない!
さらに、各ファイルに存在するSHA-1に対する暗号解読衝突攻撃をすでに実行して検出できます。 cr-marcstevens/sha1collisiondetection
Git自体に同様のチェックを追加すると、計算コストが発生しますます。
ハッシュの変更について、Linuxのコメント:
ハッシュのサイズとハッシュアルゴリズムの選択は、独立した問題です。
あなたはおそらく256ビットのハッシュに切り替え、それを内部とネイティブのgitデータベースで使用し、デフォルトでは40文字の16進文字列としてのみ ハッシュを表示します(私たちはすでに物事を省略しているように多くの状況)。
そうすれば、特別な "--full-hash
"引数(または "--abbrev=64
"またはその他-デフォルトは40に短縮されます)で渡されない限り、gitの周りのツールは変更を認識しません。
それでも、(SHA1から別のハッシュ関数への)移行計画は依然として複雑ですが、積極的に研究されています。キャンペーンはある進行中:
convert-to-object_id
3月20日更新:GitHubが攻撃の可能性とその保護について詳しく説明します。
SHA-1名には、さまざまなメカニズムを通じて信頼を割り当てることができます。たとえば、Gitを使用すると、コミットまたはタグに暗号で署名できます。これにより、コミットまたはタグオブジェクト自体にのみ署名します。これは、SHA-1名を使用して、実際のファイルデータを含む他のオブジェクトをポイントします。これらのオブジェクトの衝突により、有効であるように見えるが、署名者が意図したものとは異なるデータを指す署名が生成される場合があります。このような攻撃では、署名者には衝突の半分しか見えず、被害者には残りの半分が見えます。
保護:
最近の攻撃では、特別な手法を使用して、SHA-1アルゴリズムの弱点を悪用して、より短時間で衝突を発見しています。これらの手法は、衝突ペアのいずれかの半分のSHA-1を計算するときに検出できるパターンをバイトに残します。
GitHub.comは、計算するSHA-1ごとにこの検出を実行し、オブジェクトが衝突ペアの半分であるという証拠がある場合は操作を中止します。これにより、攻撃者がGitHubを使用して、プロジェクトの「無害な」半分の衝突を受け入れるように説得したり、悪意のある半分をホストしたりすることを防ぎます。
マークスティーブンスの「sha1collisiondetection
」を参照
繰り返しになりますが、2018年第1四半期のGit 2.16にハッシュアルゴリズムを表す構造が追加されたことで、新しいハッシュへの遷移の実装が開始されました。
上記のように、新しくサポートされるハッシュはSHA-256になります。
git-svn
間接的ではありますが、間接的にではありますが、「これには何らかの問題があります」のリンクがそれを参照しています)
暗号学者は祝うと思います。
SHA-1に関するWikipediaの記事からの引用:
2005年2月、Xiaoyun Wang、Yiqun Lisa Yin、Hongbo Yuによる攻撃が発表されました。攻撃は、フルバージョンのSHA-1で衝突を見つけることができ、必要な操作は2 ^ 69未満です。(ブルートフォース検索には2 ^ 80の操作が必要です。)
y
つまり、h(x) ==
h(y) `はSSL証明書などの任意のデータに対する深刻な脅威であることがわかりますが、これはGitには影響しません。メッセージを持つx
メッセージにそれを修正することができるx'
というh(x) == h(x')
。したがって、この攻撃はGitを弱めません。また、Gitはセキュリティ上の理由からSHA-1を選択していません。
SHA-1のようなハッシュにはいくつかの異なる攻撃モデルがありますが、通常議論されるのは、Marc StevensのHashClashツールを含む衝突検索です。
人々が指摘したように、gitとのハッシュ衝突を強制することはできますが、そうしても別のリポジトリの既存のオブジェクトが上書きされることはありません。git push -f --no-thin
既存のオブジェクトを上書きすることはないと思いますが、100%確実ではありません。
つまり、リモートリポジトリにハッキングした場合、偽のオブジェクトをそこにある古いオブジェクトにして、ハッキングされたコードをgithubなどのオープンソースプロジェクトに埋め込むことができます。注意していた場合は、新しいユーザーがダウンロードしたハッキングされたバージョンを導入することができます。
ただし、プロジェクトの開発者が行う可能性のある多くのことは、数百万ドルのハックを公開したり、誤って破壊したりする可能性があると思います。特に、あなたがハッキングしなかった開発者がgit push --no-thin
、影響を受けるファイルを変更した後、--no-thin
依存関係がなくても前述のものを実行した場合、それは多額のお金になります。