最近,一组研究人员生成了两个具有相同SHA-1哈希值的文件(https://shattered.it/)。
由于Git使用这个哈希值进行内部存储,这种类型的攻击对Git有多大影响?
最近,一组研究人员生成了两个具有相同SHA-1哈希值的文件(https://shattered.it/)。
由于Git使用这个哈希值进行内部存储,这种类型的攻击对Git有多大影响?
编辑,2017年12月末:Git版本2.16正在逐步获得内部接口,以允许使用不同的哈希值。还有很长的路要走。
macbook$ shasum shattered-*
38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-1.pdf
38762cf7f55934b34d179ae6a4c80cadccbb7f0a shattered-2.pdf
macbook$ cmp shattered-*
shattered-1.pdf shattered-2.pdf differ: char 193, line 8
macbook$ git init
Initialized empty Git repository in .../tmp/.git/
macbook$ git add shattered-1.pdf
macbook$ git add shattered-2.pdf
macbook$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: shattered-1.pdf
new file: shattered-2.pdf
macbook$ git ls-files --stage
100644 ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0 0 shattered-1.pdf
100644 b621eeccd5c7edac9b7dcba35a8d5afd075e24f2 0 shattered-2.pdf
ba9aa...
和 b621e...
,它们都不是38762c...
。为什么呢?原因是Git将文件存储为字符串文字blob
、一个空格、十进制表示的文件大小和ASCII NUL字节,然后才是文件数据。两个文件的大小完全相同。macbook$ ls -l shattered-?.pdf
... 422435 Feb 24 00:55 shattered-1.pdf
... 422435 Feb 24 00:55 shattered-2.pdf
因此,两者都以文本字面值 blob 422435\0
为前缀(其中 \0
表示单个字节,类似于 C 或 Python 中的八进制转义字符串)。
也许并不令人惊讶,如果您了解 SHA-1 的计算方式,给两个不同的文件添加相同的前缀,即使在之前产生了 相同的校验和,也会导致它们现在产生 不同的 校验和。
这个结果不足为奇的原因是,如果最终的校验和结果对于每个输入位的位置和值都不是极其敏感的话,那么只需重新排列已知的输入文件中的一些位,就可以轻松制造碰撞。 尽管这两个输入文件在char 193, line 8
处有不同的字节,但研究人员通过尝试超过9千亿(short scale)的输入才实现了相同的总和。为了得到这个结果,他们放入了一些在他们控制下影响总和的原始数据块,直到找到产生碰撞的输入对。
通过添加blob
头,Git改变了位置,仅发生了一次意外的错位就摧毁了110个GPU年的计算。
现在,知道Git会这样做后,他们可以使用以blob 422435\0
开头的输入重复他们的110 GPU年计算(前提是他们的牺牲块没有被推动太多;而实际所需的GPU年计算数量可能会有所不同,因为该过程有点随机)。然后,他们将得到两个不同的文件,这些文件可以去掉blob
头。这两个文件现在具有不同的SHA-1校验和,但是当使用git add
添加时,两个文件将产生相同的SHA-1校验和。
shattered-3.pdf
。) 一个足够好的Git - 我不确定当前的Git是否如此出色; 请参见Ruben's experiment-based answer到How would Git handle a SHA-1 collision on a blob? - 将注意到git add shattered-4.pdf
,试图添加第二个文件,与第一个但不同的shattered-3.pdf
相撞,并会警告您并失败git add
步骤。 在任何情况下,您都无法将这些文件都添加到单个存储库中。
但首先,必须有人花费更多的时间和金钱来计算新的哈希碰撞。