关于php:密码安全随机字符串函数

Cryptographically Secure Random String Function

目标:找到最安全的密码随机字符串生成器。使用字母、数字以及字符串中可能的特殊字符。

我一直在这里和其他地方阅读,但我仍然听到许多不同的答案/意见。了解最新安全和密码技术的人能在这里插话吗?

以下函数将用于生成8个字符的随机密码,并生成128个字符的随机令牌。

功能1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * Used for generating a random string.
 *
 * @param int $_Length  The lengtyh of the random string.
 * @return string The random string.
 */

function gfRandomString($_Length) {
    $alphabet ="abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < $_Length; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

功能2:

php.net文档说:加密强:如果传递到函数中,这将保存一个布尔值,该值确定所使用的算法是否"加密强",例如,对于gpg、密码等的使用是安全的;如果是,则为真;否则为假。

这是基于服务器的吗?如果我测试它一次,它就能够生成一个加密的强字符串,它总是能够吗?或者我需要每次检查并创建一个循环,直到它生成一个加密字符串。

1
2
3
4
5
6
7
8
9
10
/**
 * Used for generating a random string.
 *
 * @param int $_Length  The length of bits.
 * @return string The random string.
 */

function gfSecureString($_Length) {
    $Str = bin2hex(openssl_random_pseudo_bytes($_Length));
    return $Str;
}

我欢迎任何提高密码强度的建议。


所以您希望在PHP中安全地生成随机字符串。问题中的两个函数都不能满足您的需要,但rand()解决方案是这两个函数中最糟糕的。rand()不安全,而bin2hex(openssl_random_pseudo_bytes())限制输出字符集。

此外,在极端条件或异国环境下,openssl_random_pseudo_bytes()可能不可靠。

据我所知,只有当RAND_pseudo_bytes()没有返回任何数据时,crypto_strong才会设置为false。如果在调用openssl时未对其进行种子设定,它将静默返回弱(可能是可预测的)伪随机字节。在PHP中,您无法确定它是否是随机的。

今天如何生成安全随机字符串

如果您想要一个已经得到php 5.x大量审查的解决方案,请使用randomlib。

1
2
3
$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
$randomPassword = $generator->generateString(20, $alphabet);

替代解决方案

如果您不想使用randomlib(即使纯粹是因为您希望有其他选项可用),当php 7出现时,您也可以使用random_int()。如果你不能等到那时,看看我们的随机兼容项目。

如果您碰巧使用了密码库libnadium,您可以生成这样的随机数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Depends on the PECL extension libsodium
 *
 * @link https://stackoverflow.com/a/31498051/2224584
 *
 * @param int $length How long should the string be?
 * @param string $alphabet Contains all of the allowed characters
 *
 * @return string
 */

function sodium_random_str($length, $alphabet = 'abcdefghijklmnopqrstuvwxyz')
{
    $buf = '';
    $alphabetSize = strlen($alphabet);
    for ($i = 0; $i < $length; ++$i) {
        $buf .= $alphabet[\Sodium
andombytes_uniform($alphabetSize)];
    }
    return $buf;
}

请参阅这个答案,例如使用random_int()的代码。如果将来需要的话,我宁愿不重复更新代码的工作。


openssl_random_pseudo_bytes有很大的机会成为一个加密安全的生成器,而rand当然不是。但是,它只返回二进制数据,您可以将其还原为十六进制。十六位小数不足以生成密码字符串。两个函数都不包含您似乎需要的特殊字符。

所以这两个代码片段都不符合您的目的。