git中的哈希冲突


175

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

例如,我设法用相同的sha1校验和提交两个文件,git会注意到它还是损坏其中一个文件?

可以改进git来使其兼容吗,还是我必须更改为新的哈希算法?

(请不要通过讨论这种可能性的可能性来避免这个问题-谢谢)


26
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
KurzedMetal

16
绝对不是这样。引用丹·伯恩斯坦的话:“学者们还没有进行过SHA-1碰撞攻击,这是一次历史性的小事故。”-SHA-3竞赛已经结束,相关人员很有可能会引起他们的注意使用已知的攻击来产生碰撞。马克·史蒂文斯(Marc Stevens)估计难度仅为2 ^ 61次操作。SHA-1碰撞很可能很快就会出现。奇怪的是还没有发生。
保罗·克劳利

27
@KurzedMetal:有机会在欧洲核子研究中心(CERN)上创建一个黑洞(两个质子会准确碰撞(10 ^ -15m)),但是这个黑洞不会吸收地球,由于霍金辐射会立即蒸发…… SHA1碰撞的可能性比被吸吮要大得多...只是说...
Jaa-c


17
令人惊讶的是,您明​​确要求人们不要讨论git碰撞的可能性,而几乎每个人都在谈论git碰撞的可能性。这些人一生都应被禁止使用stackoverflow!
福泽由纪夫(Yukio Fukuzawa)

Answers:


108

在10个卫星上拾取原子

SHA-1哈希是一个40进制字符串...每个字符4位乘以40 ... 160位。现在我们知道10位大约是1000位(准确地说是1024位),这意味着有10000000000000000000000000000000000000000000000000000000000000000 SHA-1哈希... 10 48

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

扩展这个我们可以问一个问题...

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

这与所谓的“生日攻击”有关,后者又称为“生日悖论”或“生日问题”,它指出当您从给定集合中随机选择时,您极有可能需要很少的选择采了两次 但是“令人惊讶地很少”在这里是一个相对的术语。

维基百科上有一张关于生日悖论碰撞概率的表格。没有用于40个字符的哈希的条目。但是对32个字符和48个字符的条目进行插值会使我们落在5 * 10 22 git commit 的范围内,发生冲突的可能性为0.1%。那就是五千亿次不同的提交,或五十个Zetta提交,在您甚至有0.1%的机会发生碰撞之前。

仅这些提交的哈希字节总和就比一年内在地球上生成的所有数据都多,这意味着您需要比YouTube流视频输出更快的代码。祝你好运。:D

关键是除非有人故意造成碰撞,否则随机发生碰撞的可能性非常小,您可以忽略此问题

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

好的,假设确实发生了这种可能性,或者假设有人设法裁定了故意的SHA-1哈希冲突。那会发生什么呢?

在这种情况下,有人进行了试验一个很好的答案。我将引用该答案:

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

如您所见,有些情况不好。特别是案例2和案例3弄乱了您的存储库。但是,故障似乎仍然存在于该存储库中,并且攻击/怪诞的可能性不可能传播到其他存储库。

同样,故意碰撞的问题似乎也被认为是真正的威胁,因此,例如GitHub正在采取措施来防止它


22
我不知道这些数字是否准确,但是天哪,这是描述
可能性的

4
我现在正在与NASA联系,以找到10颗卫星并进行尝试。除非我们有10颗卫星,否则没人告诉它是否有效;)
Utkarsh Kumar

2
实际文本文件的随机提交发生冲突的机会高达零,非常不可能。但是,这个答案完全跳过了有人可以尝试并故意造成碰撞的事实。随着SHA-1哈希受到攻击,这已成为一个相当重要的因素。
Maarten Bodewes

7
否决票的理由:说得很好,但是概率在这里绝对没有任何意义。关于赢得乐透,您可以说同样的话,但是人们每天都在这里和那里赢得乐透。因此,乐透公司不能真的说:机会很小,因此我们不必担心实际支付头奖。OP在这里的问题是:当机会很小而您没有回答时会发生什么。
福泽由纪夫(Yukio Fukuzawa)

3
@FukuzawaYukio没有打印2 ^ 48张彩票-但是只有数百万张(也许每年总计2亿张。.谁知道?),并且有中奖彩票。概率要高得多,对于某些彩票,总是打印中奖彩票;因此,中奖者是不可避免的(除非中奖彩票被意外放错了)。同样,多年前,我制作了一个伪现实的彩票游戏:lottery.py。不用说,您会损失99%的时间。
dylnmc

67

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

请参阅“开始思考sha-256?”主题中的Linus Torvalds的帖子。在git邮件列表中


4
“如果两个文件在git中具有相同的哈希值,它将把这些文件视为相同。” 这实际上是一个正确的答案。但是,您对klaustopher的声明有何了解?您的链接对我不起作用。
蒂亚戈

3
但这并不是绝对不可能的,如果您在一个带有哈希冲突样本集合的项目上工作。
Doomjunky

6
@JBishop不,不是。如果您确实有哈希冲突的证明,那么您将一举成名。别忘了发布!如果您告诉我一周之内在Git中创建的全尺寸SHA-1哈希碰撞,我将发送一箱真正优质的哈勒姆啤酒。请注意,它必须是单独的哈希冲突,而不是已经在其他地方引用的哈希冲突(不是任何人都已经发布过,但是仍然如此)。
Maarten Bodewes

7
+1到目前为止,唯一可以实际回答问题的答案。所有其他一切都只是在谈论它可能发生的“小机会”,这是每个开发人员都已经知道的。
福泽由纪夫(Yukio Fukuzawa)

2
对于Linus讨论IT安全性要非常警惕-他以前做错了,在这一点上做错了。如果可以随意创建SHA-1冲突,则可以将其用于各种混乱,例如创建导致Git服务器和客户端崩溃的循环历史记录。
DomQ '18

26

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

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

那么,那对Git意味着什么呢?不多。散列很少(相对于其他所有散列)完成,以至于运算的总体代价较低。发生两次碰撞的机会非常低,这不是现实的机会,因此不会立即被发现(即,您的代码很可能突然停止构建),从而允许用户解决问题(备份版本,并再次进行更改,由于时间的变化,您几乎肯定会获得不同的哈希值,该哈希值也以git的形式提供。如果您在git中存储任意二进制文件,那么对您来说可能是一个真正的问题,这实际上并不是主要用途模型。如果您想这样做...最好使用传统数据库。

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


4
you'll almost certainly get a different hash because of the time change, which also feeds the hash in git哈希不是仅基于文件的内容吗?
fredoverflow

4
Blob的哈希值基于文件的内容(带有少量的元数据),但是提交的哈希值(理论上也可能发生冲突)包含当前时间以及树的哈希值,作者,父级提交的哈希等。但是,正如@Steve指出的那样,小事情不太可能发生冲突,而提交则是小事情。
cdyson37 2015年

1
不要以为我同意“数据越短,冲突就越少”。如果您指的是更短的哈希,那么您将减少可能的哈希集=更多的输入映射到每个哈希=更高的碰撞机会。如果您是指要散列的短消息,那么这仅在可能输入的数量受所用字符数量限制的意义上才是正确的,这似乎很明显,我觉得我一定很想念您的观点吗?
基本

我从未想到过“非常相似”的观点,这是一个非常好的观点。基本上,这意味着为了使2个提交具有相同的哈希,您需要在每个文件中更改大部分字符(更不用说文件名,路径和文件数)。
PieterNuyts

1
@PieterNuyts否,为了从任意初始文件中获取特定的哈希,通常必须更改文件中的信息,其数量类似于哈希中信息的位数,即,大约160位SHA-1。但是,有关更改哪些位的信息也在此处计算,因此文件越长,如果选择正确的位,则必须更改的位就越少。假设,给定一个长度超过2 ^ 160字节的文件,通过更改单个位,您几乎可以获得任何哈希,因为该位的位置承载着160多个信息!
M克洛斯特

10

可以改进git来使其兼容吗,还是我必须更改为新的哈希算法?

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


我认为您是说“不太可能”或“不太可能”,对吗?当然,您可以将输出更改为字节数更少的哈希算法,但这不是您的意思,对吧?:)
MichaelK

2
SHA-1从某种意义上被打破,从而有可能产生故意的哈希冲突。我认为也已经在2012年。因此,更改为更安全且状态和输出更大的其他哈希肯定会有所作为。
Maarten Bodewes

9

您可以在“ Git如何处理Blob上的SHA-1碰撞? ”中看到很好的研究。

由于SHA1碰撞现在可以(我在引用这个答案shattered.io),知道了Git 2.13(Q2 2017)将提高/使用的“检测企图制造冲突”变种缓解目前的状况SHA1实现作者:马克·史蒂文斯(CWI)和丹·舒莫(Microsoft)

请参阅Jeff King()的提交f5f5e7f提交8325e43提交c0c2006提交45a574e提交28dc98e(2017年3月16日(通过合并JUNIOÇ滨野- -提交48b3693 3月24日2017)peff
gitster

Makefile:使 DC_SHA1默认

我们以前默认使用OpenSSL库中的SHA1实现。
由于我们在最近的“崩溃”声明后要努力防止碰撞攻击,因此请切换默认值以鼓励人们使用DC_SHA1实现。
那些想使用OpenSSL实施的人可以OPENSSL_SHA1=YesPlease在运行“ make” 时明确要求它。

实际上,我们没有Git与对象的碰撞,因此,我们能做的最好的事情就是通过test-sha1运行一个破碎的PDF。这将触发碰撞检查并死亡。


可以改进Git来使其兼容吗,还是我必须更改为新的哈希算法?

2017年12月使用Git 2.16 更新(2018年第一季度):支持替代SHA的工作正在进行中:请参阅“ 为什么Git不使用更现代的SHA? ”。

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


Git 2.18(Q2 2018)记录了该过程。

提交5988eb6提交45fa195通过(2018年3月26日)ÆvarArnfjörðBjarmason( )avar
(通过合并JUNIOÇ滨野- gitster-提交d877975 4月11日2018)

doc hash-function-transition:阐明“破碎”的含义

尝试弄清楚“破碎”攻击在实践中对Git意味着什么。
文本的先前版本没有提及Git已经对该特定攻击进行了缓解的任何方法,粉碎的研究人员声称,它将检测到密码分析冲突攻击。

我可能误会了一些细微差别,但据我所知,新文本准确地总结了git中SHA-1的当前情况。即git不再使用SHA-1,而是使用Hardened-SHA-1(它们恰好在99.99999999999 ...%的时间内产生相同的输出)。

因此,先前的文本在断言以下方面是错误的:

[...]由于[不完整]的结果,SHA-1不再被认为是加密安全的[...]

事实并非如此。我们可以缓解SHATHETED的问题,但是 我们认为,应谨慎处理NewHashSHA-1或Hardened-SHA-1中将来的漏洞。

因此,新文档现在显示为:

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:请参见``为什么Git不使用更现代的SHA? ''


4
这是这里唯一的体面的答案或评论。摘要是-尽管极不可能,但有可能。它们也将立即变得无法识别,并通过调整文件(带有注释)来避免冲突,从而加以纠正。人们认为故意利用是无关紧要的,因为有人可以很容易地签入“错误代码”,并且程序中存在诸如签名和蓄意拉取请求之类的东西,可防止随机人员检入随机物品。
布拉德(Brad)

5

Google现在声称在某些前提下有可能发生SHA-1碰撞: https //security.googleblog.com/2017/02/announcing-first-sha1-collision.html

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

IMO,git绝对应该使用更好的哈希算法,因为现在有可能发生故意的冲突。


2
同样,不信任Linus关于计算机安全性的说法也是明智的。他以前做错了,在这一方面他做错了。(例如,SHA-1冲突
预告片

2

哈希冲突极不可能发生,以至于令人震惊!全世界的科学家都在努力实现这一目标,但尚未实现。但是对于某些算法(例如MD5),它们还是成功的。

几率是多少?

SHA-256具有2 ^ 256个可能的哈希。大约是10 ^ 78。或更确切地说,发生碰撞的机会大约为

1:10000亿000000000 000000000000 000000000000

赢得彩票的机会约为1:14Mio。与SHA-256发生碰撞的机会就像连续11天赢得彩票!

数学解释:14000000 ^ 11〜2 ^ 256

此外,宇宙大约有10 ^ 80个原子。仅比SHA-256组合多100倍。

成功的MD5碰撞

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

d131dd02c5e6eec4 693d9a0698aff95c 2fcab5 8 712467eab 4004583eb8fb7f89
55ad340609f4b302 83e4888325 7 1415a 085125e8f7cdc99f d91dbdf280373c5b
d8823e3156348f5b ae6dacd436c919c6 dd53e2 b 487da03fd 02396306d248cda0
e99f33420f577ee8 ce54b67080 a 80d1e c69821bcb6a88393 96f965 2 b6ff72a70

与MD5相同

d131dd02c5e6eec4 693d9a0698aff95c 2fcab5 0 712467eab 4004583eb8fb7f89
55ad340609f4b302 83e4888325 f 1415a 085125e8f7cdc99f d91dbd7280373c5b
d8823e3156348f5b ae6dacd436c919c6 dd53e2 3 487da03fd 02396306d248cda0
e99f33420f577ee8 ce54b67080 2 80d1e c69821bcb6a88393 96f965 a b6ff72a70

这并不意味着MD5的算法已经破解,因此它的安全性有所降低。您可以故意创建MD5冲突,但是偶然的MD5冲突的机会仍然是2 ^ 128,这仍然很多。

结论

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


4
这个答案主要是关于SHA-256的,这与问题无关,因为问题是关于SHA-1的。显示SHA-256碰撞不太可能的数学结果比SHA-1产生的乐观结果要乐观得多。这仍然不太可能,但是SHA-1的答案更有意义。
安德鲁·阿诺特

@AndrewArnott SHA-256和SHA-1之间没有相关区别。SHA-1的强度要弱2 ^ 128倍,但这也没有关系。它仍然不是易碎的,所以我的回答并没有那么错位。
bytecode77

4
SHA-1确实被破坏了,因此说它“仍然不可破碎”也是不正确的。鉴于SHA-1实际上已损坏,可以想象有人可以故意攻击git的sha-1算法来替换内容而不会被检测到。SHA-256尚未损坏,因此它将更加安全。因此,回答有关潜在git冲突的问题最好保留在SHA-1中。
Andrew Arnott

“这并不意味着MD5的算法已经破解,因此它的安全性降低了。” 再来?你能解释一下这句话吗?
Maarten Bodewes

回答的原因:因为在不熟悉计算的人中仍然有很多困惑,他们仍然从搜索网络中降落。根据我的经验,对“加密与计算能力”的误解比您想像的更为普遍,因此我将其作为补充信息加以解决。
bytecode77


1

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

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

海报声称:

我使用git rebase遇到一次哈希冲突。

不幸的是,他没有提供任何证据。但是也许您想与他联系并询问他有关此事件的信息。

但是,从更一般的角度来看,由于生日攻击,pow(2,80)中发生SHA-1哈希冲突的机会为1。

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

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

如果开发人员非常依赖于变基,则每次为分支运行变基时,该分支的所有版本(或该分支的变基部分)中的所有提交都会获得新的哈希值。对于每个用“ git filter-branch”修改的文件,情况也是如此。因此,“哈希值”和“过滤器分支”对于随着时间的推移生成的哈希数可能是很大的乘数,即使实际上并没有全部保留它们:通常,在重新定基础后(尤其是为了“清理”分支的目的) ),原来的分支将被丢弃。

但是,如果碰撞发生在调整基准或过滤器分支期间,则仍可能产生不利影响。

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

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

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

对于80亿人口的100个存储库,得出的pow(2,47)与pow(2,80)仍然相去甚远。

但是,这不包括上述假定的乘法效果,因为我不确定如何将其包括在此估计中。可能会大大增加碰撞的机会。尤其是如果很多人将非常长的提交历史(例如Linux Kernel)的大型存储库基于微小的更改重新建立了基础,而这些更改却为所有受影响的提交创建了不同的哈希值。


有趣。+1。如上所述,这个问题最终将消失:stackoverflow.com/a/47838703/6309
VonC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.