使用PHP 5.6生成范围内的安全随机整数

时间:2015-09-23 06:55:45

标签: php security random entropy

我想在PHP5.6中生成$min$max之间的安全随机整数。 PHP中的rand()mt_rand()都被认为不是加密安全的。

来自docs

  

注意

     

此函数不会生成加密安全值,也不应用于加密目的。如果您需要加密安全值,请考虑使用random_int(),random_bytes()或openssl_random_pseudo_bytes()代替。

PHP 7添加random_int()docs),完全符合我的用例:

  

random_int - 生成加密安全的伪随机整数

但是如何在PHP 5.6中实现此功能?

我天真的尝试是这样的:

<?php
function secure_rand($min, $max)
{
    return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}

但是在调用secure_rand(1, 100)时,我似乎总是得到“2”。我还读到,以这种方式使用模数运算可能会产生偏差。如何在PHP 5.6中模拟random_int()

3 个答案:

答案 0 :(得分:3)

我可能会向您介绍{3}在PHP 5项目中填充random_bytes()random_int()的问题吗? (旁注:在其他项目中,它在4.4版本中被Wordpress收录。)

function secure_rand($min, $max)
{
    return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}

即使这是你想做的事情,当($max - $min)不是2的偶数幂时,这是random_compat

答案 1 :(得分:2)

找到了一个非常好的解决方案。在示例中,使用了mcrypt扩展,但如果您需要更多信息here,它也适用于openssl_random_pseudo_bytes()

function secure_rand( $min, $max ) {
    $diff = $max - $min;
    if ($diff < 0 || $diff > 0x7FFFFFFF) {
        throw new RuntimeException("Bad range");
    }
    $bytes = mcrypt_create_iv( 4, MCRYPT_DEV_URANDOM );

    // if mcrypt is not enabled on your server, you can use this
    //$bytes = openssl_random_pseudo_bytes( 4 );

    // if mbstring is not enabled, you can also use iconv_strlen
    if ($bytes === false || mb_strlen($bytes, '8bit') != 4) {
        throw new RuntimeException("Unable to get 4 bytes");
    }

    $ary = unpack("Nint", $bytes);
    $val = $ary['int'] & 0x7FFFFFFF;   // 32-bit safe
    $fp = $val / 2147483647.0; // convert to [0,1]
    // if you really need a type of int take this
    // return (int) round($fp * $diff) + $min;
    // otherwise it will return a float without decimal numbers
    return round($fp * $diff) + $min;
}

var_dump( secure_rand( 1, 1000 ) );
var_dump( secure_rand( 1, 20 ) );
var_dump( secure_rand( 1, 10 ) );
var_dump( secure_rand( 1, 5000 ) );
var_dump( secure_rand( 1, 1111111 ) );

已更新源代码中的注释,已删除强制转换为float / int,使用mb_strlen()代替strlen()

答案 2 :(得分:0)

您可以使用 openssl_random_pseudo_bytes ,因为自PHP 5.3起可用

  

生成一串伪随机字节,字节数由length参数确定。

     

它还指示是否使用加密强算法来生成伪随机字节,并通过可选的crypto_strong参数执行此操作。这种情况很少见,但有些系统可能会被破坏或过时。

PHP docs

了解详情