【问题标题】:Cryptographically secure unique id加密安全的唯一 ID
【发布时间】:2015-10-05 17:36:13
【问题描述】:

我想使用 php 生成加密安全的唯一 uuid。

uniqid() 提供唯一但不安全的 ID,而 openssl_random_pseudo_bytes() 提供安全但不唯一的 ID。两者的结合(以下代码)是正确的方法还是有更好的解决方案?

uniqid(bin2hex(openssl_random_pseudo_bytes(10)), true);

【问题讨论】:

    标签: php security uuid prng php-openssl


    【解决方案1】:

    我想使用 php 生成加密安全的唯一 uuid。

    好的,这很容易做到。

    uniqid() 提供唯一但不安全的 ID,openssl_random_pseudo_bytes() 提供安全但不唯一的 ID。

    是什么让您认为 cryptographically secure pseudorandom number 不是唯一的?

    /**
     * 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://stackoverflow.com/a/31460273/2224584
     * @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 specification,使用了PHP7的random_bytes()函数。

    对于 PHP 5 项目,您可以使用 random_compat 从 PHP 7 中填充 random_bytes()

    【讨论】:

    【解决方案2】:

    尽管最佳答案实际上是正确的,但理论上并不正确。

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

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

    UUIDv4 的优势在于,两次获得相同 ID(碰撞)的概率非常小,“两次从星系中挑选同一个原子”的概率很小。

    任何增加唯一性的尝试实际上都会降低安全性。您可以添加微秒时间戳或自动递增值和毫米精度空间坐标以保证唯一性。但随后您添加了有关创建 ID 的位置、方式和顺序的信息......

    同样,出于所有实际目的,使用 UUIDv4 作为安全且唯一的标识符是安全的。

    还要意识到md5sha1uniqid 等本身并不完美,以随机方式组合它们并不一定会减少碰撞或增加安全性。散列函数充其量与您正在散列的事物一样唯一,并且通常它们会降低唯一性。

    答案总是在于随机性加上长度。

    【讨论】:

    • 我们实际上是在谈论大于数十亿面的骰子,而您将相同的东西滚动 x 次的概率恰好是 n^x。这是一个天文数字,需要 6,610 年的处理能力才能找到 sha1 碰撞。此外,将它们结合起来确实可以通过概率的乘积减少碰撞。
    【解决方案3】:

    为什么不对 openssl_random_pseudo_bytes 的输出进行哈希处理? 您还可以连接时间戳并在之后对其进行哈希处理

    md5(bin2hex(openssl_random_pseudo_bytes(10)).strval(time()));
    

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

    【讨论】:

    • 那会达到什么效果?
    • MD5 不是一种安全的哈希算法。
    猜你喜欢
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-12
    • 2012-03-18
    • 1970-01-01
    • 2010-10-29
    相关资源
    最近更新 更多