【问题标题】:Hash collision in gitgit中的哈希冲突
【发布时间】:2012-05-13 03:24:30
【问题描述】:

如果我在使用 git 时发生哈希冲突,实际会发生什么?

例如我设法提交了两个具有相同 sha1 校验和的文件, git 会注意到它或损坏其中一个文件吗?

可以改进 git 以适应这种情况,还是我必须更改为新的哈希算法?

(请不要通过讨论不太可能来转移这个问题 - 谢谢)

【问题讨论】:

  • I've been informed by the git Gods that the chances of a SHA1 collision is the same as the Earth being sucked up into the black hole created by the CERN accelerator. If this is indeed true, then there's no need for that extra memcmp. ,来源:lwn.net/Articles/307281
  • 绝对不是这样。引用 Dan Bernstein 的话:“学术界还没有进行 SHA-1 碰撞攻击的事实是一个小小的历史事故”——现在 SHA-3 竞赛已经结束,相关人士很有可能会转移注意力使用已知的攻击来产生碰撞。 Marc Stevens 估计难度仅为 2^61 次操作。很可能很快就会出现 SHA-1 碰撞;奇怪的是它还没有发生。
  • @KurzedMetal:有机会在 CERN 中制造黑洞(两个质子会精确碰撞 (10^-15m)),但是这个黑洞不会吸走地球,它会立即蒸发由于霍金辐射...所以 SHA1 碰撞的机会比被吸的要大得多...只是说...
  • 令人惊讶的是,你特地要求人们不要讨论 git 冲突的可能性,而几乎每个人都在谈论 git 碰撞的可能性。这些人应该被终身禁止使用stackoverflow!

标签: git hash sha1 hash-collision


【解决方案1】:

可以改进 git 以适应这种情况,还是我必须更改为新的哈希算法?

任何散列算法都可能发生冲突,因此更改散列函数并不能排除问题,它只会降低发生的可能性。所以你应该选择一个非常好的哈希函数(SHA-1 已经是,但你要求不要被告知:)

【讨论】:

  • 我认为您的意思是“不太可能”或“不太可能”,对吧?当然,您可以更改为输出中包含 less 个字节的哈希算法,但这不是您的意思,对吧? :)
  • SHA-1 在某种意义上被破坏了,因为它可能会产生故意的哈希冲突。我想它已经在 2012 年了。因此,更改为更安全且具有更大状态和输出的不同哈希肯定会有所作为。
【解决方案2】:

如果两个文件在 git 中具有相同的哈希值,它会将这些文件视为相同。在绝对不可能发生这种情况的情况下,您总是可以返回一个提交,并更改文件中的某些内容,这样它们就不会再发生冲突了......

Linus Torvalds' post in the thread “Starting to think about sha-256?” in the git mailing list

【讨论】:

  • "如果两个文件在 git 中具有相同的哈希值,它会将这些文件视为相同。"这实际上是一个正确的答案。但是,你有这个声明 klaustopher 的一些来源吗?您的链接对我无效。
  • 但是,如果您从事的项目包含哈希冲突样本集合,这并非绝对不可能。
  • @JBishop 不,它没有。如果您确实有哈希冲突的证明,您将立即成名。不要忘记发布它!如果您在一周内向我展示在 Git 中创建的全尺寸 SHA-1 哈希冲突,我将送一箱真正优质的哈勒姆啤酒。请注意,它必须是单独的哈希冲突,而不是已经在其他地方引用过的(不是任何人已经发布过,但仍然如此)。
  • +1 迄今为止唯一真正回答问题的答案。其余的人都在喋喋不休地谈论它可能发生的“小概率”,每个开发人员都已经知道了。
  • 对 Linus 讨论 IT 安全性要非常警惕——他以前错了,这次他错了。如果可以随意创建 SHA-1 冲突,则可以将其用于各种混乱,例如创建导致 Git 服务器和客户端崩溃的循环历史。
【解决方案3】:

如果不解释为什么这不是问题,就不可能用正确的“但是”来回答这个问题。如果没有真正掌握哈希的真正含义,就不可能做到这一点。它比您在 CS 程序中可能遇到的简单案例要复杂。

这里对信息论有一个基本的误解。如果您通过丢弃一些数量(即哈希)将大量信息减少为更少量的信息,则可能会发生与数据长度直接相关的冲突。数据越短,它就越不可能。现在,绝大多数碰撞都是乱码,使它们更有可能实际发生(你永远不会检查乱码......即使是二进制图像也有点结构化)。最后,机会很渺茫。要回答您的问题,是的,git 会将它们视为相同,更改哈希算法无济于事,需要进行某种“第二次检查”,但最终,您将需要尽可能多的“附加检查”数据因为数据的长度是 100% 确定的...请记住,您将是 99.99999....到一个非常长的数字....确定像您描述的那样进行简单检查。 SHA-x 是加密强哈希,这意味着通常不难故意创建两个彼此非常相似且具有相同哈希的源数据集。数据中的一点变化应该在散列输出中产生不止一个(最好尽可能多)位的变化,这也意味着从散列返回到完整的一组非常困难(但并非完全不可能)冲突,从而从那组冲突中提取出原始消息——除了少数之外,所有的都是乱码,如果消息长度足够长,那么在那些没有的消息中仍然有大量需要筛选。加密哈希的缺点是它们的计算速度很慢……一般来说。

那么,这对 Git 意味着什么?不多。哈希很少(相对于其他所有内容)完成,以至于它们的计算代价总体上对操作来说很低。发生一对碰撞的机会是如此之低,它不是一个现实的机会发生并且不会立即被检测到(即您的代码很可能会突然停止构建),允许用户解决问题(备份修订,并再次进行更改,由于时间更改,您几乎肯定会得到不同的哈希,这也提供了 git 中的哈希)。如果您在 git 中存储任意二进制文件,这对您来说更有可能是一个真正的问题,这并不是它的主要使用模型。如果您想这样做...您可能最好使用传统数据库。

考虑这一点并没有错——这是一个很好的问题,很多人只是假装“不太可能,不值得考虑”——但实际上比这要复杂一些。如果它确实发生了,它应该很容易被检测到,它不会是正常工作流程中的无声损坏。

【讨论】:

  • you'll almost certainly get a different hash because of the time change, which also feeds the hash in git 哈希值不只是基于文件的内容吗?
  • blob 的哈希基于文件的内容(带有少量元数据),但是提交的哈希(理论上也可能发生冲突)包含当前时间,如以及树的哈希、作者、父提交的哈希等。但是,正如@Steve 指出的那样,小事情不太可能发生冲突,提交是一件小事。
  • 不要以为我同意“数据越短,[冲突] 的可能性就越小”。如果您的意思是更短的散列,那么您正在减少可能的散列集=更多的输入映射到每个散列=更高的冲突机会。如果您的意思是要散列的消息较短,那么这仅在可能输入的数量受使用的字符数限制的意义上是正确的,这似乎很明显,我觉得我一定错过了您的意思?
  • 我从没想过“非常相似”这一点,这是一个非常好的观点。这基本上意味着为了让 2 次提交具有相同的哈希值,您需要更改每个文件中的大部分字符(更不用说文件名、路径和文件数)。
  • @PieterNuyts 不,为了从任意初始文件中获取特定的哈希值,您通常必须将文件中的信息更改为类似于散列,即 SHA-1 大约 160 位。但是,有关要更改的位的信息也很重要,因此文件越长,如果您选择正确的位,您必须更改的位就越少。假设,给定一个长度远高于 2^160 字节的文件,您可以通过更改单个位来获得几乎任何散列,因为该位的位置包含超过 160 位的信息!
【解决方案4】:

在 10 个卫星上挑选原子

SHA-1 哈希是 40 个十六进制字符串...即每个字符 4 位乘以 40...160 位。现在我们知道 10 位大约是 1000(准确地说是 1024),这意味着有 1 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 个不同的 SHA-1 哈希... 1048支持>.

这相当于什么?那么月球是由大约 1047 个原子组成的。因此,如果我们有 10 颗卫星……而你在其中一颗卫星上随机选择一个原子……然后继续在它们上再次选择一个随机原子……那么你可能会两次选择同一个原子, 是两个给定 git 提交具有相同 SHA-1 哈希的可能性。

对此我们可以提出问题...

在您开始担心冲突之前,您需要在存储库中提交多少次?

这与所谓的“生日攻击”有关,后者又指“生日悖论”或“生日问题”,即当你从给定的集合中随机选择时,你需要惊人的少数选择才能获得更多很可能没有选择两次。但“令人惊讶的少数”在这里是一个非常相对的术语。

维基百科有a table on the probability of Birthday Paradox collisions。没有 40 个字符的哈希条目。但是 32 和 48 个字符的条目的插值使我们处于 5*1022 git 提交的范围内,碰撞概率为 0.1%。那是 50,000 亿次不同的提交,或 50 个 Zettacommits,在你达到 0.1% 的机会之前,你发生了冲突。

仅这些提交的哈希字节总和将比地球上一年生成的所有数据更多的数据,也就是说,您需要比 YouTube 流式传输视频更快地生成代码。祝你好运。 :D

重点是,除非有人故意造成碰撞,否则随机发生碰撞的概率非常小,您可以忽略此问题

“但是当碰撞确实发生时,实际发生了什么?”

好吧,假设不可能的事情确实发生了,或者假设有人设法定制了a deliberate SHA-1 hash collision。然后会发生什么?

在这种情况下有an excellent answer where someone experimented on it。我将引用该答案:

  1. 如果已存在具有相同哈希的 blob,则根本不会收到任何警告。一切似乎都正常,但是当您推送、有人克隆或您还原时,您将丢失最新版本(符合上述说明)。
  2. 如果树对象已经存在并且您使用相同的哈希创建了一个 blob:一切看起来都很正常,直到您尝试推送或有人克隆您的存储库。然后你会看到这个 repo 已经损坏了。
  3. 如果提交对象已经存在并且您使用相同的哈希创建了一个 blob:与 #2 相同 - 损坏
  4. 如果 blob 已经存在并且您使用相同的哈希创建提交对象,则更新“ref”时它将失败。
  5. 如果 blob 已经存在,并且您使用相同的哈希创建树对象。创建提交时会失败。
  6. 如果树对象已经存在并且您使用相同的哈希创建提交对象,则更新“ref”时它将失败。
  7. 如果一个树对象已经存在并且你创建了一个具有相同散列的树对象,那么一切看起来都没有问题。但是当您提交时,所有存储库都会引用错误的树。
  8. 如果一个提交对象已经存在,并且您使用相同的哈希创建一个提交对象,那么一切看起来都正常。但是当您提交时,将永远不会创建提交,并且 HEAD 指针将移动到旧提交。
  9. 如果一个提交对象已经存在并且你用相同的哈希创建一个树对象,创建提交时它会失败。

如您所见,有些情况并不好。特别是案例 #2 和 #3 会弄乱您的存储库。但是,故障似乎确实存在于该存储库中,并且攻击或奇异的可能性不会传播到其他存储库。

此外,故意碰撞的问题似乎被认为是一个真正的威胁,例如GitHub is taking measures to prevent it

【讨论】:

  • 我不知道这些数字是否准确,但天哪,这是描述可能性的一种很好的图形方式,而且很有趣:)
  • @UtkarshKumar 有趣的部分将是验证原子数是否正确。祝他们好运。 :D
  • 实际文本文件的随机提交发生冲突的可能性几乎为零,非常不可能。但是这个答案完全忽略了有人可以尝试故意制造碰撞的事实。随着 SHA-1 哈希值受到攻击,这正成为一个相当重要的因素。
  • 投反对票的原因:说得非常好,但概率在这里绝对没有任何意义。关于中奖,你也可以这么说,但人们每天都在这里和那里赢得乐透。所以乐透公司不能真的只是说:机会很小,所以我们不必担心实际支付头奖。 OP 的问题是:当那个小机会发生而你没有回答时会发生什么。
  • @FukuzawaYukio 但是,没有打印 2^48 张彩票——只有数百万(每年可能总共 2 亿……谁知道呢?),并且有中奖彩票。概率要高得多,而且对于一些彩票,总是打印中奖彩票;所以,中奖者是不可避免的(除非中奖票不小心放错了地方)。另外,我多年前制作了一个伪现实的彩票游戏:lottery.py。不用说,你有 99% 的时间都输了。
【解决方案5】:

哈希冲突的可能性极小,简直令人震惊!全世界的科学家都在努力实现这一目标,但还没有成功。不过,对于某些算法,例如 MD5,它们是成功的。

赔率是多少?

SHA-256 有 2^256 个可能的哈希值。这大约是 10^78。或者更形象地说,碰撞的可能性大约是

1 : 100 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000

中奖概率约为1:14 Mio。与 SHA-256 发生冲突的几率就像在 连续 11 天中中奖一样!

数学解释:14 000 000^11~2^256

此外,universe 有大约 10^80 个原子。这只是 SHA-256 组合的 100 倍。

MD5 碰撞成功

即使对于 MD5,机会也很小。不过,数学家设法制造了碰撞:

d131dd02c5e6eec4 693d9a0698aff95c 2fcab58712467eab 4004583eb8fb7f89
55ad340609f4b302 83e488832571415a 085125e8f7cdc99f d91dbdf280373c5b
d8823e3156348f5b ae6dacd436c919c6 dd53e2b487da03fd 02396306d248cda0
e99f33420f577ee8 ce54b67080a80d1e c69821bcb6a88393 96f9652b6ff72a70

与 MD5 相同

d131dd02c5e6eec4 693d9a0698aff95c 2fcab50712467eab 4004583eb8fb7f89
55ad340609f4b302 83e4888325f1415a 085125e8f7cdc99f d91dbd7280373c5b
d8823e3156348f5b ae6dacd436c919c6 dd53e23487da03fd 02396306d248cda0
e99f33420f577ee8 ce54b67080280d1e c69821bcb6a88393 96f965ab6ff72a70

这并不意味着 MD5 现在其算法已被破解,安全性降低。可以故意制造MD5碰撞,但是意外MD5碰撞的几率还是2^128,还是很多的。

结论

您不必担心碰撞。散列算法是检查文件相同性的第二种最安全的方法。唯一更安全的方法是二进制比较。

【讨论】:

  • 这个答案主要是关于 SHA-256,这是无关紧要的,因为问题是关于 SHA-1。显示 SHA-256 冲突可能性的数学比 SHA-1 得出的结果要乐观得多。这仍然不太可能,但 SHA-1 的答案会更相关。
  • @AndrewArnott SHA-256 和 SHA-1 之间没有相关区别。 SHA-1 弱 2^128 倍,但这也没关系。它仍然不是易碎的,所以我的答案并没有如此放错地方。
  • SHA-1 is indeed broken 所以说它“仍然不可破坏”也是不正确的。鉴于 SHA-1 实际上已被破坏,可以想象有人会故意攻击 git 的 sha-1 算法以替换内容而不被发现。 SHA-256 还没有被破解,所以会更安全。因此,回答有关潜在 git 冲突的问题最好使用 SHA-1。
  • “这并不意味着 MD5 的算法被破解后安全性降低了。”再来?你能解释一下那句话吗?
  • 答案的原因:因为在不熟悉计算并且仍然通过搜索网络来到这里的人中存在很多困惑。根据我的经验,关于“加密与计算能力”的误解比您想象的要普遍,因此我将其作为附加信息加以解决。
【解决方案6】:

Google 现在声称在某些先决条件下可能发生 SHA-1 冲突: https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html

由于 git 使用 SHA-1 来检查文件完整性,这意味着 git 中的文件完整性受到损害。

IMO,git 绝对应该使用更好的哈希算法,因为现在可以进行故意碰撞。

【讨论】:

  • 另外,谨慎的做法是不要相信 Linus 关于计算机安全的话。他以前错了,这次他错了。 (例如,SHA-1 冲突预言机允许创建循环提交历史以崩溃服务器和客户端)
【解决方案7】:

好吧,我想我们现在知道会发生什么了 - 您应该预料到您的存储库会损坏 (source)。

【讨论】:

    【解决方案8】:

    你可以在“How would Git handle a SHA-1 collision on a blob?”看到一个很好的研究。

    由于现在可能发生 SHA1 冲突(正如我在 this answershattered.io 中引用的那样),知道 Git 2.13(2017 年第二季度)将通过“检测尝试创建冲突”变体改善/缓解当前情况SHA-1 implementation by Marc Stevens (CWI) and Dan Shumow (Microsoft).

    参见Jeff King (peff)commit f5f5e7fcommit 8325e43commit c0c2006commit 45a574ecommit 28dc98e(2017 年 3 月 16 日)。
    (由Junio C Hamano -- gitster -- 合并到commit 48b3693, 2017 年 3 月 24 日)

    Makefile:将DC_SHA1设为默认

    我们曾经使用 OpenSSL 库中的 SHA1 实现 默认。
    由于我们在最近的“破碎”公告之后试图小心防止碰撞攻击,因此切换默认值以鼓励人们改用 DC_SHA1 实现。
    那些想要使用 OpenSSL 实现的人可以明确要求 运行“make”时由OPENSSL_SHA1=YesPlease 提供。

    我们实际上并没有 Git 对象冲突,所以我们能做的最好的事情就是通过 test-sha1 运行其中一个破碎的 PDF。这应该会触发碰撞检查并死亡。


    是否可以改进 Git 以适应这种情况,或者我是否必须更改为新的哈希算法?

    2017 年 12 月更新 Git 2.16(2018 年第一季度):支持替代 SHA 的努力正在进行中:请参阅“Why doesn't Git use more modern SHA?”。

    您将能够使用另一种哈希算法:SHA1 不再是 Git 的唯一算法。


    Git 2.18(2018 年第二季度)记录了该过程。

    参见Ævar Arnfjörð Bjarmason (avar)commit 5988eb6commit 45fa195(2018 年 3 月 26 日)。
    (由 Junio C Hamano -- gitster -- 合并于 commit d877975,2018 年 4 月 11 日)

    doc hash-function-transition:澄清 SHAttered 的含义

    尝试阐明 SHAttered 攻击在实践中的意义 Git.
    先前版本的文本没有提到 Git 已经针对这种特定攻击提供了缓解措施,而 SHAttered 研究人员声称这将检测到密码分析冲突攻击。

    我可能弄错了一些细微差别,但据我所知 新文本准确地总结了 SHA-1 的现状 混帐。 IE。 git 不再真正使用 SHA-1,它使用 Hardened-SHA-1(它们恰好产生相同的输出 99.99999999999...% 的时间)。

    因此,前面的文字断言不正确:

    [...]由于[SHAttered],不能考虑SHA-1 加密更安全[...]

    事实并非如此。我们有针对 SHAttered 的缓解措施,然而 我们认为谨慎的做法是朝着NewHash 的方向前进 出现 SHA-1 或 Hardened-SHA-1 中的漏洞。

    所以new documentation 现在变为:

    Git v2.13.0 及之后的版本移至强化的 SHA-1 默认实现,不易受到 SHAttered 的影响 攻击。

    因此,Git 实际上已经迁移到不是 SHA-1 的新哈希 并且不分享它的漏洞,它的新哈希函数只是 恰好为所有已知输入产生完全相同的输出, 除了 SHAttered 研究人员发布的两份 PDF 文件和新的 实现(由那些研究人员编写)声称检测未来 密码分析碰撞攻击。

    无论如何,谨慎的做法是跳过 SHA-1 的任何变体 到一个新的哈希。不能保证未来对 SHA-1 的攻击不会 将来发布,这些攻击可能不可行 缓解措施。

    如果要真正破坏 SHA-1 及其变体,Git 的哈希函数 不能再被认为是加密安全的。这个会 影响哈希值的通信,因为我们无法信任 给定的哈希值代表已知的好版本内容 说话者的意图。

    注意:同一份文档现在(2018 年第三季度,Git 2.19)明确将 “新哈希”引用为 SHA-256:请参阅“Why doesn't Git use more modern SHA?”。

    【讨论】:

    • 这是这里唯一合适的答案或评论。总结是 - 虽然极不可能,但它是可能的。它们也将立即无法识别,并通过调整文件(带有注释)来避免冲突。故意利用被认为是无关紧要的,因为有人可以很容易地签入“坏代码” - 并且有诸如签名和故意拉取请求之类的东西来阻止随机人员签入随机内容。
    • 感谢您的精彩总结。
    【解决方案9】:

    我最近在 BSD 讨论组中发现了 2013-04-29 的帖子

    http://openbsd-archive.7691.n7.nabble.com/Why-does-OpenBSD-use-CVS-td226952.html

    发帖人声称的地方:

    我曾经遇到过一次哈希冲突,使用 git rebase。

    不幸的是,他没有为他的主张提供任何证据。但也许你想尝试联系他并询问他关于这个假定的事件。

    但在更一般的层面上,由于生日攻击,SHA-1 哈希冲突的机会是 1 in pow(2, 80)。

    这听起来很多,而且肯定比世界上所有 Git 存储库中存在的单个文件版本的总和还要多。

    但是,这仅适用于实际保留在版本历史记录中的版本。

    如果开发人员非常依赖 rebase,则每次为分支运行 rebase 时,该分支的所有版本(或分支的 rebase 部分)中的所有提交都会获得新的哈希值。每个使用“git filter-branch”修改的文件也是如此。因此,“rebase”和“filter-branch”可能是随时间生成的散列数量的大乘数,即使它们实际上并没有被保留:经常,在变基之后(特别是为了“清理”一个分支),原来的分支被扔掉了。

    但如果在 rebase 或 filter-branch 期间发生冲突,它仍然会产生不利影响。

    另一件事是估计 git 存储库中散列实体的总数,并查看它们与 pow(2, 80) 的距离。

    假设我们有大约 80 亿人,他们都将运行 git,并将他们的东西保存在每人 100 个 git 存储库中。让我们进一步假设平均存储库有 100 个提交和 10 个文件,每次提交只有一个文件更改。

    对于每个修订,我们至少有一个树对象和提交对象本身的哈希。加上更改后的文件,每个修订版有 3 个哈希值,因此每个存储库有 300 个哈希值。

    对于 80 亿人的 100 个存储库,这给出的 pow(2, 47) 与 pow(2, 80) 相差甚远。

    但是,这不包括上面提到的假设乘法效应,因为我不确定如何将它包括在这个估计中。也许它可以大大增加发生碰撞的机会。尤其是如果许多人对具有较长提交历史的非常大的存储库(如 Linux 内核)进行了重新调整以进行小的更改,但仍会为所有受影响的提交创建不同的哈希值。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-21
    • 2017-09-28
    相关资源
    最近更新 更多