使用 MD5 验证小文件(小于 15kb)的完整性是否安全?

信息安全 哈希 md5 sha256
2021-08-17 11:39:39

我知道自 90 年代以来就记录了 MD5 的冲突,并且基于 MD5 的数字证书已被证明在 2010 年被完全破坏,但 MD5 在确保少量数据未被篡改方面的效果如何?

我有一些小文本文件,大小只有几页(比如说 15kb)。我一直在对它们使用 SHA-256,但是能够使用 MD5 代替会更方便。

MD5 作为这些 15kb 小文本文件的哈希摘要的安全性如何?恶意方是否能够为如此少量的数据产生冲突,或者小规模是否使这成为一项困难的努力?

4个回答

输入的大小无关紧要。事实上,由于生日悖论,只要消息的大小超过散列的大小,就会保证发生冲突。避免冲突的最佳方法是使用不易受冲突影响的更强哈希,例如 SHA-2。但是,您描述的是一种比碰撞攻击更困难的攻击,称为原像攻击,MD5 可以避免这种攻击。

存在三种类型的攻击*会导致两个文件具有相同的摘要:

  • 第一个原像- 查找解析为特定哈希的输入。

  • 第二个原像- 修改输入而不更改结果哈希。

  • 碰撞- 查找具有相同哈希的任意两个不同输入。

当它们可以比蛮力搜索更有效地执行时,这些漏洞就是漏洞。冲突仍然可以自然发生,事实上,由于鸽巢原理,任何非平凡的输入量都可以保证它们,但哈希旨在使其难以故意执行。对于具有 MD5 大小的输出的散列,随机、意外碰撞的可能性极低。即使您每秒散列 60 亿个随机文件,也需要 100 年才能获得两个散列冲突的 50% 机会。MD5非常适合检测意外损坏。

一个强大的n位散列函数被设计为具有 2 n的安全级别来对抗第 1 次和第 2 次原像攻击,以及 2 n /2的安全级别来对抗碰撞攻击。对于像 MD5 这样的 128 位哈希,这意味着它被设计为针对原像具有 2 128的安全级别和针对冲突的2 64安全级别。随着攻击的改进,它可以提供的实际安全级别正在慢慢消失。

MD5易受碰撞攻击的影响,只需要相当于 2 18次哈希调用,而不是预期的 2 64次即可利用。除非攻击者生成两个文件,否则它不是碰撞攻击。拥有文件并想要在不更改哈希值的情况下恶意修改它的攻击者需要发起第二次原像攻击,这对于现代技术的 MD5是完全不可行的(最好的攻击复杂度为 2 123.4,与 MD5 的理论相比最多 2 128)。碰撞攻击在不同的情况下是相关的。例如,如果给您一个攻击者制作的没有后门的可执行文件,您可以对其进行哈希处理并保存哈希值。该可执行文件稍后可能会被后门版本替换,但哈希值将与良性版本相同!这对于证书来说也是一个问题,其中有人可以为他们拥有的域提交证书,但该证书会故意与他们不拥有的域的证书发生冲突。

使用 MD5 验证文件是安全的,只要存储的哈希不受篡改并且可以被信任是正确的,并且只要正在验证的文件不是由攻击者创建(或影响!)。然而,使用更强的散列可能仍然是一个好主意,只是为了防止将来针对 MD5 的潜在实际原像攻击将您的数据置于危险之中。如果您想要一个非常快但仍然加密安全的现代哈希,您可能需要查看BLAKE2

* 虽然还有其他针对 MD5 的攻击,例如影响所有 Merkle–Damgård 哈希的长度扩展攻击,正如@LieRyan 所提到的,但这些与针对已知正确的哈希验证文件的完整性无关。

一种称为选择前缀冲突攻击的冲突攻击变体能够获取两个任意消息(前缀)并找到两个值,当附加到每个消息时,会产生一个冲突摘要。这种攻击比经典的碰撞攻击更难实施。与长度扩展攻击一样,这仅适用于 Merkle-Damgård 哈希。

这取决于您要保护自己免受什么侵害

安全从来都不是一刀切的游戏。如果是,那么就不会有 12941 种不同的哈希算法。相反,您需要了解每项安全措施都可以保护您免受特定类型的攻击。您在计算机中输入密码是为了防止随机人访问它,而不是因为whereD1DweG0sowron6每次登录时输入密码都很有趣。

至于哈希算法,您可以将它们大致分为“加密哈希”和“非加密哈希”。加密哈希算法旨在抵御多种攻击,而非加密哈希旨在尽可能快。例如, 1 MD5 被认为是加密散列,但由于其破坏性太强,只能用作非加密散列。

何时使用非加密哈希

如果您的目标是在将文件从一个位置复制到另一个位置(例如,将拇指驱动器复制到笔记本电脑)时检测位翻转,那么 MD5 绝对是正确的选择。我什至会说任何快速的非加密哈希都是好的。当您复制文件时,您实际上不必担心攻击者的干扰。如果您对黑客能够修改您的内核感到偏执,那么添加哈希不会解决您的问题。

在攻击者干预的情况下验证文件完整性

如果您打算签署和发布这些文件,那么攻击者可能有能力制作具有相同哈希的可能合法文件 - 这意味着您的签名在恶意文件上同样有效。

一个例子

假设您的原始消息m1如下所示:

我在此声明,兔子规则!

您使用散列函数h(m1)并获得摘要d1之后,您签署摘要d1并获得签名s1

然后您发布您的消息m1、您的签名s1和您的散列函数h()

我可能是该场景中的攻击者,并m2在您选择的哈希函数中制作了一条具有完全相同哈希的消息:

众所周知,狗在各方面都比兔子好……

因为h(m1) = h(m2) = d1,签名s1对你的原始m1和我的恶意都有效m2

为了保护自己免受此类攻击,选择具有高抗冲突性的强大哈希算法至关重要。这意味着我很难找到m2where h(m2) = h(m1)

不错的选择包括 SHA256 和 SHA512,以及其他许多。似乎每个人都有一些喜欢的非主流哈希函数,但 SHA256 和 SHA512 的支持非常广泛,你很难找到不支持这些哈希的系统。而且由于您的文件非常小,因此计算哈希应该几乎是即时的。

例如,在我的 800MHz 机器上,计算 16k 随机文件的 SHA512 哈希需要 3ms,因此即使在烤面包机上也应该相对较快。


1 您可以使用随机数生成器看到同样的情况。加密 PRNG 旨在提供非常难以猜测的随机数,而非加密 PRNG 旨在仅提供乍一看随机的数字并快速完成。

简短回答:不,使用 MD5 验证文件的完整性是不安全的,无论是短文件还是长文件。

完整的答案取决于您对错误分布的信心

由于在串行端口等稍微有损的通道上传输,文件中每个位置是否存在独立的随机位翻转机会?如果是这样,您可以使用 MD5,但使用 CRC 会便宜得多,它可以保证检测单个位翻转,并且可以通过 CRC 多项式的标准选择来保证检测所有奇数位翻转。

但是您询问了安全,这表明您正在考虑比有损串行端口更聪明的对手。 如果你不相信的错误是独立的随机位翻转,那么就不要使用MD5或CRC。 智能攻击者很容易找到共享共同 MD5 哈希或 CRC 校验和的不同文件对,并且在许多情况下,这可以使攻击者伪造您的 MD5 系统无法检测到的文档。文件的大小无关紧要:在短至 64 字节的文件中很容易找到 MD5 冲突,并且对它们的长度没有限制。

有一个地方可以讨论碰撞攻击、原像攻击和第二原像攻击之间的技术差异。关于验证文件完整性是否安全的一般问题的答案不是这样的地方。当您有一个特定的协议时,您可以清楚地表达对手的精确权力以及合法用户在协议中的行为方式,并且您有限制您选择散列函数的实现约束,因此您必须考虑 MD5,然后我们可以讨论(也许在 crypto.SE 上)在该协议中使用 MD5 来获得您希望针对此类对手实现的安全性是否安全

但对您来说,只使用 SHA-2、SHA-3 或 BLAKE2 会更简单、更安全。

大小本身并不是很重要,实际的碰撞数据可以小到一个块。

但是,使用一组文本文件比使用一组 pdf 文件或类似文件要安全得多。

为什么?因为碰撞攻击的结果通常会导致该对的两个文件都包含一些“随机垃圾”。在丰富的格式中,这种看似随机的垃圾可以隐藏起来,因此攻击者可以欺骗收集管理员接受他们的一对冲突文件中的一个。

但是,在文本文件中,每个人都可以看到内容。