为什么MD5的UUID不是个好主意?

rye*_*guy 20 php md5 cryptography

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

在用法示例中,它显示以下内容:

$token = md5(uniqid());

但在评论中,有人这样说:

从唯一ID生成MD5是天真的,并且减少了唯一ID的大部分价值,并且在MD5域上提供了显着的(可攻击的)限制.这是一件非常破碎的事情.正确的方法是单独使用唯一ID; 它已经适应了非碰撞.

为什么这是真的,如果是这样的话?如果MD5哈希对于唯一ID(几乎)是唯一的,那么md5对uniqid有什么不对?

Con*_*lls 36

UUID是128位宽,并且具有生成方式固有的唯一性.MD5散列是128位宽,并不保证唯一,只有较低的碰撞概率.MD5哈希不小于UUID,因此它对存储没有帮助.

如果您知道散列来自UUID,那么攻击就容易得多,因为如果您知道有关机器生成它们的任何信息,那么有效UUID的域实际上是可预测的.

如果您需要提供安全令牌,则需要使用加密安全随机数生成器.(1)UUID不是设计为加密安全的,只保证唯一.由唯一机器标识符(通常是MAC)和时间限制的单调递增序列仍然是完全有效的UUID,但如果您可以从令牌序列中反向设计单个UUID,则可高度预测.

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

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


Fer*_*yer 13

请注意,uniqid()它不会返回UUID,而是根据当前时间返回 "唯一"字符串:

$ php -r 'echo uniqid("prefix_", true);'
prefix_4a8aaada61b0f0.86531181
Run Code Online (Sandbox Code Playgroud)

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

md5()输出的优点,以及特定于应用程序的盐字符串或随机数,是一种更难猜测字符串的方法:

$ php -r 'echo md5(uniqid("prefix_", true));'
3dbb5221b203888fc0f41f5ef960f51b
Run Code Online (Sandbox Code Playgroud)

与普通的不同uniqid(),它每微秒产生非常不同的输出.此外,它不会显示您的"前缀盐"字符串,也不会在您uniqid()的引擎盖下使用.在不知道盐的情况下,猜测下一个ID非常困难(认为不可能).

总而言之,我不同意评论员的意见,并且总是更喜欢md5()-ed输出而不是普通的uniqid().

  • 如果你需要你的ID是不可思议的,那么采取一个容易猜测的输入并对其进行模糊处理是不可取的. (3认同)
  • 有非常好的方法可以生成真正不可猜测的 ID。仅仅通过混淆一个容易预测的序列,你就依赖于没有人弄清楚方法和你的盐串。如果他们这样做,他们可以轻松预测您将来会生成的 ID。 (2认同)
  • 基于相同的理由,你可以说每个基于密码的加密算法都很弱,因为你依赖于没有人搞清楚密码.然而,问题是关于将MD5与PHP的uniqid()函数一起使用,而不是关于生成不可思议的唯一ID的最佳方法. (2认同)
  • Salt 必须是随机数据。使用相同的“prefix_”只会混淆,它是不安全的。 (2认同)

Ada*_*kin 5

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

  • 事实上,情况更糟,因为 UUID 是唯一的,而 UUID 的 MD5 哈希值却不是。 (2认同)