【问题标题】:PHP rand() vs. random_int()PHP rand() 与 random_int()
【发布时间】:2017-10-28 22:47:50
【问题描述】:

作为php.net indicates: random_int() 函数生成加密安全的伪随机整数

但是,有人能解释一下rand()random_int() 之间的区别吗?当只需要一个随机整数时,我可以使用random_int() 而不是rand() 吗?哪个更快?

【问题讨论】:

  • php.net/manual/en/function.random-int.php "返回一个加密的安全随机整数,范围从 min 到 max,包括。"php.net/manual/en/function.rand.php "此函数不生成加密安全值”
  • 使用rand(),除非你需要一个安全的随机整数,然后使用random_int()。如果你不知道你是否需要后者,你可能不需要(它会影响“可猜测性”,所以想象一下它在哪里有用)。例如,如果您尝试随机播放幻灯片,rand() 就可以了。
  • 关于速度的事情,除非你知道你需要它,否则不要在此基础上过早优化。专注于函数的应用,然后在必要时调整效率。
  • mt_rand() 在 PHP 7.1 中取代了 rand()。只是想知道为什么没有提到?

标签: php php-7


【解决方案1】:

重新审视这个问题并看到给出的答案,我发现我将我的 cmets 提交给一个答案是公平的,因为他们之前已经提交过。

PHP 7 的 random_int() 函数手册指出:

“返回从 min 到 max 范围内的加密安全随机整数。”

对于rand()

*此函数不生成加密安全值" *

OP 的评论:

“@Fred-ii- 谢谢。但是“加密安全伪随机”是什么意思?- NDFA”

根据我的发现,可以在以下链接中找到:

其中规定:

加密安全伪随机数生成器 (CSPRNG) 或加密伪随机数生成器 (CPRNG)[1] 是一种伪随机数生成器 (PRNG),其特性使其适用于密码学.


关于性能,您需要自己运行基准测试。

【讨论】:

  • 我同意。很高兴将您的答案作为参考留在这里(因为我认为随着 php 开发人员切换到 7 这个问题会引起更多关注)。
  • 确实@NDFA 干杯
【解决方案2】:

从 PHP 7.1 开始,rand()mt_rand() 的别名。较新的random_int() 是三种方法中最慢但唯一安全的方法。

<?php

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += rand(0, 32767);
}
printf('[rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += mt_rand(0, 32767);
}
printf('[mt_rand] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 10000000; $i++) {
    $sum += random_int(0, 32767);
}
printf('[random_int] Time: %.3f s%s', microtime(true) - $start, PHP_EOL);

PHP 7.4 的结果:

[rand] Time: 0.320 s      
[mt_rand] Time: 0.326 s   
[random_int] Time: 9.255 s

【讨论】:

    【解决方案3】:

    rand()

    rand() 现在是mt_rand() 的别名。查看source code of mt_rand(),可以看出随机数根本不是随机的。这是一个简单的数学计算,并不比

    复杂多少
    return $min + suffle_bits($internal_counter++) % ($max - $min);
    

    其中suffle_bits() 是一些可预测的二进制算术,使$internal_counter 看起来不仅仅是自增。

    这就是为什么rand() 被称为返回伪随机数字的原因。返回的数字似乎是随机抽取的,但知道$internal_counter 的值可以让您预测接下来会发生什么。

    random_int()

    random_int() 不会受到这种可预测性问题的影响,前提是计算机的熵发生器已正确启动。

    即使攻击者收集了大量值,也无法猜测下一个值。

    哪个最好

    如果攻击者可以从您的代码输出中猜出$internal_counter 的值并利用该知识干扰您的代码的预期用途,请使用random_int()

    如果使用随机数来显示,比如说,随机问候,那么rand() 是绝对安全的。

    现在,如果必须生成一长串 GUID 或条形码,并且最终用户不能从子集中猜测另一个有效值,那么 random_int() 不仅在安全性方面更好,而且因为它不会重复自己。 rand() 可能会以 32768 输出的速度重复自身,具体取决于平台。

    哪个更快

    毫无疑问,rand() 更简单,因此也更快。

    这是一个粗略的单行易于复制/粘贴的命令,用于计算在 10 秒内可以从rand() 中抽取多少个数字:

    php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10){rand(0,9);$c++;};echo "$c\n";'
    

    random_int() 也是如此:

    php -r '$s=microtime(true);$c=0;while(microtime(true)-$s<10){random_int(0,9);$c++;};echo "$c\n";'
    

    php 7.3 的计数器是:

    rand():       36665142
    random_int(): 10511327
    

    rand() 的速度不到 4 倍。除非速度是一个问题,否则random_int() 是可行的方法,但对于最基本的非关键任务。

    【讨论】:

      【解决方案4】:

      与大多数数字生成器一样,使用 rand() 并不安全,因为它不会生成加密安全值,而且 rand() 的输出是可预测的。

      PHP 7.0 引入了 random_bytes 和 random_int 作为核心函数,解决了大多数随机数生成器存在的问题。

      【讨论】:

      • 那是错误的。首先,这不是问题,它是设计使然,像 rand() 这样的加密不安全函数通常比加密安全函数快,所以如果你不将它用于与安全相关的事情,最好使用非安全函数。您无法真正比​​较加密安全和加密不安全的功能,它们的用法确实不同。
      【解决方案5】:

      我个人在使用 random_int 时没有遇到任何问题,但它应该与 try/catch 一起使用,因为如果无法收集足够的熵,它会引发异常。

      【讨论】:

        【解决方案6】:

        补充Frédéric 响应,在PHP 8.0.3 中,random_int() 似乎比以前快了很多,使用他自己的代码示例。

        与:

        <?php
            echo "this will take 20 seconds\n\n";
            
            echo "generating random with 'rand' method\n";
            $s1=microtime(true);$c1=0;while(microtime(true)-$s1<10){rand(0,65535);$c1++;};
            $fc1 = number_format($c1 , 0, ',', '.');
            echo "generated: $fc1\n\n";
            
            echo "generating random with 'random_int' method\n";
            $s2=microtime(true);$c2=0;while(microtime(true)-$s2<10 {random_int(0,65535);$c2++;};
            $fc2 = number_format($c2 , 0, ',', '.');
            echo "generated: $fc2\n\n"; 
        ?>
        

        我得到了输出:

        this will take 20 seconds
        
        generating random with 'rand' method
        generated: 48.423.988
        
        generating random with 'random_int' method
        generated: 30.843.067
        

        在他的测试中,random_int()rand() 慢三倍以上。

        在这些中,random_int() 仅比 rand() 慢 40%。

        PS:我已将最大随机值从 9 增加到 65535 以供个人使用,似乎实际上提高了两种情况的速度。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-08-20
          • 2015-08-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多