【问题标题】:Why is MD5'ing a UUID not a good idea?为什么 MD5'ing UUID 不是一个好主意?
【发布时间】:2009-08-18 13:12:48
【问题描述】:

PHP 有一个 uniqid() 函数,可以生成各种 UUID。

在使用示例中,显示如下:

$token = md5(uniqid());

但在 cmets 中,someone says this:

从唯一 ID 生成 MD5 是 天真并降低了很多价值 唯一的 ID,以及提供 显着(可攻击)的限制 MD5 域。这是一个深 做坏事。正确的 方法是使用唯一的ID 它自己的;它已经为 非碰撞。

如果是这样,为什么这是真的?如果 MD5 散列(几乎)对于唯一 ID 是唯一的,那么 md5'ing uniqid 有什么问题?

【问题讨论】:

    标签: php cryptography md5


    【解决方案1】:

    UUID 为 128 位宽,并且具有其生成方式所固有的唯一性。 MD5 散列是 128 位宽,不保证唯一性,只保证低概率的冲突。 MD5 哈希值不小于 UUID,因此对存储没有帮助。

    如果您知道哈希来自 UUID,那么攻击会容易得多,因为如果您对生成它们的机器有所了解,那么有效 UUID 的域实际上是相当可预测的。

    如果您需要提供安全令牌,那么您需要使用cryptographically secure random number generator.(1) UUID 并非设计用于加密安全,仅保证唯一。由唯一机器标识符(通常是 MAC)和时间限制的单调递增序列仍然是完全有效的 UUID,但如果您可以从令牌序列中逆向工程单个 UUID,则具有高度可预测性。

    1. 加密安全 PRNG 的定义特征是给定迭代的结果不包含足够的信息来推断下一次迭代的值 - 即,生成器中有一些隐藏状态未在数字中显示,并且不能通过检查来自 PRNG 的数字序列来推断。

      如果您进入数论领域,您可以找到方法从一系列生成的值中猜测某些 PRNG 的内部状态。 Mersenne Twister 就是这种生成器的一个例子。它具有隐藏状态,它曾经获得很长一段时间,但它在密码学上并不安全 - 您可以采用相当小的数字序列并使用它来推断内部状态。完成此操作后,您可以使用它来攻击依赖于对该序列保密的加密机制。

    【讨论】:

    • 为什么 UUID 被认为是 128 位,当它有 30 个字符而不是 32 个以 16 为底的字符时?数字 13 是基数 5 (1-5),数字 17 是基数 4 (8,9,A,B)。从理论上讲,与真正的 128 位 MD5 相比,这应该会增加碰撞概率...
    【解决方案2】:

    请注意,uniqid() 不会返回 UUID,而是基于当前时间的“唯一”字符串:

    $ php -r 'echo uniqid("prefix_", true);'
    prefix_4a8aaada61b0f0.86531181
    

    如果你多次这样做,你会得到非常相似的输出字符串,熟悉uniqid()的每个人都会认出源算法。这样就很容易预测将要生成的下一个 ID。

    md5()-ing 输出以及特定于应用程序的盐字符串或随机数的优势是更难猜测字符串:

    $ php -r 'echo md5(uniqid("prefix_", true));'
    3dbb5221b203888fc0f41f5ef960f51b
    

    与普通的uniqid() 不同,它每微秒产生非常不同的输出。此外,它不会透露您的“前缀盐”字符串,也不会透露您在后台使用uniqid()。在不知道盐的情况下,很难(认为不可能)猜测下一个 ID。

    总之,我不同意评论者的观点,并且总是更喜欢md5()-ed 输出而不是普通的uniqid()

    【讨论】:

    • 如果您需要让您的 ID 不可猜测,那么采用易于猜测的输入并对其进行混淆不是可行的方法。
    • 如果不公开盐字符串(用于 uniqid() 的前缀),输入如何猜测?你能解释一下你的批评吗?
    • 有一些非常好的方法可以生成真正难以猜测的 ID。通过仅仅混淆一个容易预测的序列,你依赖于没有人弄清楚方法和你的盐字符串。如果他们这样做了,他们就可以轻松预测您将来会生成的 ID。
    • 基于相同的理由,您可以争辩说每个基于密码短语的加密算法都很弱,因为您依赖于没有人知道密码。然而,问题是关于将 MD5 与 PHP 的 uniqid() 函数一起使用,而不是关于生成不可猜测的唯一 ID 的最佳方法。
    • Salt 必须是随机数据。使用相同的“prefix_”只会混淆,并不安全。
    【解决方案3】:

    对 UUID 进行 MD5 处理毫无意义,因为 UUID 已经是唯一且固定长度(短)的,这些属性是人们经常使用 MD5 开始的一些原因。所以我想这取决于你打算用 UUID 做什么,但一般来说,UUID 与一些经过 MD5 处理的数据具有相同的属性,那么为什么两者都做呢?

    【讨论】:

    • 事实上,情况更糟,因为 UUID 是唯一的,而 UUID 的 MD5 哈希则不是。
    【解决方案4】:

    UUID 已经是唯一的,因此无论如何都没有必要对它们进行 MD5 处理。

    关于安全问题,一般来说,如果攻击者能够预测您将要生成的下一个唯一 ID 是什么,您就会受到攻击。如果已知您从 UUID 生成唯一 ID,则潜在的下一个唯一 ID 的集合要小得多,从而为暴力攻击提供更好的机会。

    如果攻击者可以从您那里获得一大堆唯一 ID,并以此猜测您生成 UUID 的方案,则尤其如此。

    【讨论】:

    • “没有意义”:事实上,这比没有意义更糟糕,因为 UUID 是唯一的,而 UUID 的 MD5 哈希则不是。
    【解决方案5】:

    Version 3 的 UUID 已经是 MD5 了,所以没有必要再做一次。但是,我不确定 PHP 使用什么 UUID 版本。

    【讨论】:

      【解决方案6】:

      顺便说一句,MD5 实际上已经过时,并且从 2010 年起不再用于任何值得保护的事物 - PHI、PII 或 PCI。美国联邦调查局已强制执行此规定,任何不合规的实体都将支付大量美元的罚款。

      【讨论】:

      • 是的。使用 MD5 进行安全性的软件将不会被正式考虑在 2010 年之后,但实际上,现在没有人想要它,因为他们将被要求稍后摆脱它(稍后很快就会有价值)。因此,如果您销售软件或软件即服务,您将仅通过使用 MD5 排除一些客户。使用 SHAx,最好使用较大的 x 值。
      • 据我所知,MD5 从未包含在 NIST 标准中。 NIST 正在逐步淘汰的是 SHA-1,基本上所有具有 80 位或更低安全性的东西。不执行 NIST 标准的公司也不会被罚款。他们只是无法获得 NIST 认证,因此失去了需要此类认证的客户。
      猜你喜欢
      • 1970-01-01
      • 2012-10-26
      • 2019-11-11
      • 2016-02-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多