在php中生成加密安全的随机数

2022-08-30 22:30:51

PHP的函数不能给出好的随机数。所以我开始使用据说能提供更好的结果。但这些结果有多好呢?有什么方法可以再次改进它们吗?rand()mt_rand()

我的想法:

function rand_best($min, $max) {
    $generated = array();
    for ($i = 0; $i < 100; $i++) {
        $generated[] = mt_rand($min, $max);
    }
    shuffle($generated);
    $position = mt_rand(0, 99);
    return $generated[$position];
}

这应该给你“完美”的随机数,不是吗?


答案 1

伪随机数生成器(PRNG)是非常复杂的野兽。

没有真正的“完美”随机数生成器 - 事实上,从数学函数中可以做到的最好的是伪随机 - 它们对于大多数意图和目的来说似乎足够随机。

事实上,从PRNG返回的数字执行任何其他操作并不能真正增加其随机性,事实上,该数字可能会变得不那么随机。

因此,我最好的建议是,不要弄乱从PRNG返回的值。使用足以满足预期用途的PRNG,如果不是,则如有必要,请找到可以产生更好结果的PRNG。

坦率地说,mt_rand函数似乎使用Mersenne twister,这是一个非常好的PRNG,因此对于大多数休闲使用来说,它可能足够好。

但是,Mersenne Twister并非设计用于任何安全环境。请参阅此答案,了解在需要随机性以确保安全性时使用的解决方案。

编辑

评论中有一个问题,为什么对随机数执行操作可以使其不那么随机。例如,一些PRNG可以在位的不同部分返回更一致,更少的随机数 - 高端可能比低端更随机。

因此,在丢弃高端并返回低端的操作中,该值的随机性可能小于从 PRNG 返回的原始值。

我目前找不到一个很好的解释,但我基于 Random.nextInt(int) 方法的 Java 文档,该方法旨在在指定范围内创建一个相当随机的值。该方法考虑了值各部分的随机性差异,因此与更朴素的实现(例如)相比,它可以返回更好的随机数。rand() % range


答案 2

快速回答:

在新的 PHP7 中,终于支持加密安全的伪随机整数。

int random_int ( int $min , int $max )

还有一个PHP5x的polyfill

更长的答案


没有完美的随机数生成器,计算机使用伪随机数生成器来创建看起来随机的序列。序列看起来是随机的(并通过了一些随机性测试),但是因为有一些算法可以生成它,所以你可以重复具有绝对相同状态的算法并获得相同的结果。

密码学相同的建议“不要发明自己的密码”可以转换为随机数生成器,这意味着您不能只是将许多随机数生成器组合在一起并期望获得更好的生成器。


随机数生成器的子集之一是加密安全的随机数生成器

普通PRNG的要求也可以通过加密安全的PRNG来满足,但事实并非如此。CSPRNG要求分为两组:第一,它们通过了统计随机性测试;其次,它们在严重攻击下保持良好状态,即使攻击者可以使用其初始或运行状态的一部分。

所以这非常接近你对“完美”的定义。再一次,在没有条件的情况下(除了学习如何进行加密),你应该尝试实现其中一种算法并在你的系统中使用它。


但幸运的是,PHP7 已经实现了它,

int random_int ( int $min , int $max )

生成加密随机整数,适用于无偏结果至关重要的情况(即洗牌扑克牌)。

随机的来源如下:

  • 在 Windows CryptGenRandom() 上被专门使用
  • 如果可用,则使用arc4random_buf(通常特定于BSD)
  • /dev/arandom 在可用时使用
  • 系统调用(在较新的 Linux 内核上)getrandom(2)
  • /dev/urandom 用于上述任何一项都不可用的情况

这使得所有以前的答案都过时了(有些被弃用了)。


推荐