密码学安全的唯一标识符

13

我希望使用php生成安全的唯一uuids。

uniqid()提供了唯一但不安全的id,而openssl_random_pseudo_bytes()提供了安全但不唯一的id。下面的代码是将两者组合起来用一个较好的方法吗?还是有更好的解决方案?

uniqid(bin2hex(openssl_random_pseudo_bytes(10)), true);
3个回答

11
我希望使用PHP生成具有密码学安全性的唯一UUID。
好的,这很容易实现。 uniqid()提供了唯一但不安全的ID,而openssl_random_pseudo_bytes()提供了安全但不唯一的ID。
你认为密码学安全的伪随机数不是唯一的吗?
/**
 * Return a UUID (version 4) using random bytes
 * Note that version 4 follows the format:
 *     xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
 * where y is one of: [8, 9, A, B]
 * 
 * We use (random_bytes(1) & 0x0F) | 0x40 to force
 * the first character of hex value to always be 4
 * in the appropriate position.
 * 
 * For 4: http://3v4l.org/q2JN9
 * For Y: http://3v4l.org/EsGSU
 * For the whole shebang: https://3v4l.org/LNgJb
 * 
 * @ref https://dev59.com/tlwZ5IYBdhLWcg3wb_-Y#31460273
 * @ref https://paragonie.com/b/JvICXzh_jhLyt4y3
 * 
 * @return string
 */
function uuidv4()
{
    return implode('-', [
        bin2hex(random_bytes(4)),
        bin2hex(random_bytes(2)),
        bin2hex(chr((ord(random_bytes(1)) & 0x0F) | 0x40)) . bin2hex(random_bytes(1)),
        bin2hex(chr((ord(random_bytes(1)) & 0x3F) | 0x80)) . bin2hex(random_bytes(1)),
        bin2hex(random_bytes(6))
    ]);
}

上面的例子符合UUIDv4规范,并使用PHP7的random_bytes()函数。
对于PHP 5项目,您可以使用random_compat来填充来自PHP 7的random_bytes()

对于使用php的人,请参考https://dev59.com/vGMk5IYBdhLWcg3w8STa#18890309,了解openssl_random_pseudo_bytes()创建加密安全唯一ID的示例。 - Goose
1
@Goose 使用random_compat,而不是openssl_random_pseudo_bytes:https://github.com/ramsey/uuid/issues/80 - Scott Arciszewski

0

尽管最高票答案在实践上是正确的,但从理论上讲并不正确。

你的问题也没有完美的答案。

安全性依赖于公正、不可预测、真正的随机性。但是,真正随机的东西可以总是重复,否则它就不会是随机的。一个有一百万面的骰子可能连续掷出同一个数字一百万次,这种情况发生的概率非常小。

UUIDv4的强大之处在于获得相同ID两次(碰撞)的概率极小,就像“从银河系中两次选择相同的原子”那样小。

任何试图增加唯一性的尝试实际上都会降低安全性。你可以添加微秒级时间戳或自动递增值和毫米精度空间坐标来保证唯一性。但是,这样做会增加关于ID创建的位置、方式和顺序的信息...

再次强调,对于所有实际目的而言,使用UUIDv4作为安全且唯一的标识符是安全的。

还要意识到,md5sha1uniqid等本身并不完美,将它们以随机方式组合并不一定会减少碰撞或增加安全性。哈希函数最多只能像你要哈希的东西一样独特,通常它们会降低独特性。

答案总是在随机性和长度之中。


我们实际上在谈论一个数值超过几十亿面的骰子,而你掷出相同点数x次的概率恰好是n^x。这是如此巨大到需要6610年的处理能力才能找到sha1碰撞。此外,将它们组合起来确实可以通过概率乘积减少碰撞。 - Bluebaron

-1
为什么不对openssl_random_pseudo_bytes的输出进行哈希处理呢? 您还可以在时间戳后连接并进行哈希处理。
md5(bin2hex(openssl_random_pseudo_bytes(10)).strval(time()));

以 md5 为例,您可以使用任何哈希算法。


那会有什么成就? - Cybergibbons
1
MD5不是一种安全的哈希算法。 - starbeamrainbowlabs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接