php 在php中生成随机密码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6101956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generating a random password in php
提问by nunos
I am trying to generate a random password in php.
我正在尝试在 php 中生成一个随机密码。
However I am getting all 'a's and the return type is of type array and I would like it to be a string. Any ideas on how to correct the code?
但是我得到了所有的 'a' 并且返回类型是数组类型,我希望它是一个字符串。关于如何更正代码的任何想法?
Thanks.
谢谢。
function randomPassword() {
$alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789";
for ($i = 0; $i < 8; $i++) {
$n = rand(0, count($alphabet)-1);
$pass[$i] = $alphabet[$n];
}
return $pass;
}
回答by Naftali aka Neal
Security warning:
rand()
is not a cryptographically secure pseudorandom number generator. Look elsewhere for generating a cryptographically secure pseudorandom string in PHP.
安全警告:
rand()
不是加密安全的伪随机数生成器。在别处寻找在 PHP 中生成加密安全伪随机字符串的方法。
Try this (use strlen
instead of count
, because count
on a string is always 1
):
试试这个(使用strlen
而不是count
,因为count
在字符串上总是1
):
function randomPassword() {
$alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
$pass = array(); //remember to declare $pass as an array
$alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
for ($i = 0; $i < 8; $i++) {
$n = rand(0, $alphaLength);
$pass[] = $alphabet[$n];
}
return implode($pass); //turn the array into a string
}
回答by Scott Arciszewski
TL;DR:
特尔;博士:
- Use
random_int()
and the givenrandom_str()
below. - If you don't have
random_int()
, use random_compat.
- 使用
random_int()
和random_str()
下面给出。 - 如果没有
random_int()
,请使用random_compat。
Explanation:
解释:
Since you are generating a password, you need to ensure that the password you generate is unpredictable, and the only way to ensure this property is present in your implementation is to use a cryptographically secure pseudorandom number generator(CSPRNG).
由于您正在生成password,您需要确保您生成的密码是不可预测的,并且确保您的实现中存在此属性的唯一方法是使用加密安全的伪随机数生成器(CSPRNG)。
The requirement for a CSPRNG can be relaxed for the general case of random strings, but not when security is involved.
对于随机字符串的一般情况,可以放宽对 CSPRNG 的要求,但在涉及安全性时则不能。
The simple, secure, and correct answer to password generation in PHP is to use RandomLiband don't reinvent the wheel. This library has been audited by industry security experts, as well as myself.
在 PHP 中生成密码的简单、安全和正确的答案是使用RandomLib并且不要重新发明轮子。这个库已经过行业安全专家和我自己的审核。
For developers who prefer inventing your own solution, PHP 7.0.0 will provide random_int()
for this purpose. If you're still on PHP 5.x, we wrote a PHP 5 polyfill for random_int()
so you can use the new API before PHP 7 is released. Using our random_int()
polyfill is probablysafer than writing your own implementation.
对于喜欢发明自己的解决方案的开发人员,PHP 7.0.0 将random_int()
为此提供支持。如果您仍在使用 PHP 5.x,我们编写了一个PHP 5 polyfill,random_int()
以便您可以在 PHP 7 发布之前使用新的 API。使用我们的random_int()
polyfill可能比编写自己的实现更安全。
With a secure random integer generator on hand, generating a secure random string is easier than pie:
手头有一个安全的随机整数生成器,生成一个安全的随机字符串比馅饼更容易:
<?php
/**
* Generate a random string, using a cryptographically secure
* pseudorandom number generator (random_int)
*
* For PHP 7, random_int is a PHP core function
* For PHP 5.x, depends on https://github.com/paragonie/random_compat
*
* @param int $length How many characters do we want?
* @param string $keyspace A string of all possible characters
* to select from
* @return string
*/
function random_str(
$length,
$keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
) {
$str = '';
$max = mb_strlen($keyspace, '8bit') - 1;
if ($max < 1) {
throw new Exception('$keyspace must be at least two characters long');
}
for ($i = 0; $i < $length; ++$i) {
$str .= $keyspace[random_int(0, $max)];
}
return $str;
}
回答by user3260409
I know you are trying to generate your password in a specific way, but you might want to look at this method as well...
我知道您正在尝试以特定方式生成密码,但您可能也想查看此方法...
$bytes = openssl_random_pseudo_bytes(2);
$pwd = bin2hex($bytes);
It's taken from the php.net site and it creates a string which is twice the length of the number you put in the openssl_random_pseudo_bytes function. So the above would create a password 4 characters long.
它取自 php.net 站点,它创建一个字符串,该字符串是您在 openssl_random_pseudo_bytes 函数中输入的数字长度的两倍。所以上面会创建一个 4 个字符长的密码。
In short...
简而言之...
$pwd = bin2hex(openssl_random_pseudo_bytes(4));
Would create a password 8 characters long.
将创建一个 8 个字符长的密码。
Note however that the password only contains numbers 0-9 and small cap letters a-f!
但请注意,密码仅包含数字 0-9 和小写字母 af!
回答by BSQ
Tiny code with 2 line.
2 行的小代码。
demo: http://codepad.org/5rHMHwnH
演示:http: //codepad.org/5rHMHwnH
function rand_string( $length ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return substr(str_shuffle($chars),0,$length);
}
echo rand_string(8);
with rand_string you can define how much character will be create.
使用 rand_string 您可以定义将创建多少字符。
回答by PeeHaa
If you are on PHP7 you could use the random_int()
function:
如果您使用的是 PHP7,则可以使用该random_int()
函数:
function generate_password($length = 20){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
'0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';
$str = '';
$max = strlen($chars) - 1;
for ($i=0; $i < $length; $i++)
$str .= $chars[random_int(0, $max)];
return $str;
}
Old answer below:
下面的旧答案:
function generate_password($length = 20){
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.
'0123456789`-=~!@#$%^&*()_+,./<>?;:[]{}\|';
$str = '';
$max = strlen($chars) - 1;
for ($i=0; $i < $length; $i++)
$str .= $chars[mt_rand(0, $max)];
return $str;
}
回答by Sandra
In one line:
在一行中:
substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 )
回答by Madara's Ghost
Your best bet is the RandomLib library by ircmaxell.
最好的选择是ircmaxell的RandomLib 库。
Usage example:
用法示例:
$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
$passwordLength = 8; // Or more
$randomPassword = $generator->generateString($passwordLength);
It produces strings which are more strongly random than the normal randomness functions like shuffle()
and rand()
(which is what you generally want for sensitive information like passwords, salts and keys).
它产生的字符串比普通的随机函数(如shuffle()
和)具有更强的随机性rand()
(这是您通常需要的敏感信息,如密码、盐和密钥)。
回答by jeteon
I'm going to post an answer because some of the existing answers are close but have one of:
我要发布一个答案,因为一些现有的答案很接近,但有一个:
- a smaller character space than you wanted so that either brute-forcing is easier or the password must be longer for the same entropy
- a RNGthat isn't considered cryptographically secure
- a requirement for some 3rd party library and I thought it might be interesting to show what it might take to do it yourself
- 比您想要的更小的字符空间,以便暴力破解更容易,或者密码必须更长才能获得相同的熵
- 不被认为是加密安全的RNG
- 对某些 3rd 方库的要求,我认为展示自己可能需要做的事情可能会很有趣
This answer will circumvent the count/strlen
issue as the security of the generated password, at least IMHO, transcends how you're getting there. I'm also going to assume PHP > 5.3.0.
这个答案将绕过这个count/strlen
问题,因为生成的密码的安全性,至少恕我直言,超越了你到达那里的方式。我还将假设 PHP > 5.3.0。
Let's break the problem down into the constituent parts which are:
让我们将问题分解为以下组成部分:
- use some secure source of randomness to get random data
- use that data and represent it as some printable string
- 使用一些安全的随机源来获取随机数据
- 使用该数据并将其表示为一些可打印的字符串
For the first part, PHP > 5.3.0 provides the function openssl_random_pseudo_bytes
. Note that whilst most systems use a cryptographically strong algorithm, you have to check so we'll use a wrapper:
对于第一部分,PHP > 5.3.0 提供了功能openssl_random_pseudo_bytes
。请注意,虽然大多数系统使用加密强算法,但您必须进行检查,以便我们使用包装器:
/**
* @param int $length
*/
function strong_random_bytes($length)
{
$strong = false; // Flag for whether a strong algorithm was used
$bytes = openssl_random_pseudo_bytes($length, $strong);
if ( ! $strong)
{
// System did not use a cryptographically strong algorithm
throw new Exception('Strong algorithm not available for PRNG.');
}
return $bytes;
}
For the second part, we'll use base64_encode
since it takes a byte string and will produce a series of characters that have an alphabet very close to the one specified in the original question. If we didn't mind having +
, /
and =
characters appear in the final string and we want a result at least $n
characters long, we could simply use:
对于第二部分,我们将使用base64_encode
它,因为它需要一个字节字符串,并将生成一系列字符,这些字符的字母表非常接近原始问题中指定的字母表。如果我们不介意在最终字符串中出现+
,/
和=
字符,并且我们希望结果至少是$n
字符长,我们可以简单地使用:
base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4))));
The 3/4
factor is due to the fact that base64 encoding results in a string that has a length at least a third bigger than the byte string. The result will be exact for $n
being a multiple of 4 and up to 3 characters longer otherwise. Since the extra characters are predominantly the padding character =
, if we for some reason had a constraint that the password be an exact length, then we can truncate it to the length we want. This is especially because for a given $n
, all passwords would end with the same number of these, so that an attacker who had access to a result password, would have up to 2 less characters to guess.
该3/4
因素是由于 base64 编码导致字符串的长度至少比字节字符串大三分之一。结果将精确为$n
4 的倍数,否则最多 3 个字符。由于额外的字符主要是填充字符=
,如果我们出于某种原因限制了密码的长度,那么我们可以将其截断为我们想要的长度。这尤其是因为对于给定的$n
,所有密码都以相同数量的密码结尾,因此可以访问结果密码的攻击者最多可以猜测 2 个字符。
For extra credit, if we wanted to meet the exact spec as in the OP's question then we would have to do a little bit more work. I'm going to forgo the base conversion approach here and go with a quick and dirty one. Both need to generate more randomness than will be used in the result anyway because of the 62 entry long alphabet.
额外的功劳,如果我们想满足 OP 问题中的确切规范,那么我们将不得不做更多的工作。我将放弃这里的基本转换方法,而采用快速而肮脏的方法。由于 62 个条目的长字母表,两者都需要生成比结果中使用的更多的随机性。
For the extra characters in the result, we can simply discard them from the resulting string. If we start off with 8 bytes in our byte-string, then up to about 25% of the base64 characters would be these "undesirable" characters, so that simply discarding these characters results in a string no shorter than the OP wanted. Then we can simply truncate it to get down to the exact length:
对于结果中的额外字符,我们可以简单地从结果字符串中丢弃它们。如果我们从字节字符串中的 8 个字节开始,那么大约 25% 的 base64 字符将是这些“不需要的”字符,因此简单地丢弃这些字符会导致字符串不短于 OP 想要的。然后我们可以简单地截断它以得到确切的长度:
$dirty_pass = base64_encode(strong_random_bytes(8)));
$pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8);
If you generate longer passwords, the padding character =
forms a smaller and smaller proportion of the intermediate result so that you can implement a leaner approach, if draining the entropy pool used for the PRNG is a concern.
如果您生成更长的密码,填充字符=
在中间结果中所占的比例越来越小,这样您就可以实施更精简的方法,如果需要担心耗尽用于 PRNG 的熵池。
回答by phihag
You want strlen($alphabet)
, not count
of the constant alphabet
(equivalent to 'alphabet'
).
您想要strlen($alphabet)
,而不是count
常量alphabet
(相当于'alphabet'
)。
However, rand
is not a suitable random function for this purpose. Its output can easily be predicted as it is implicitly seeded with the current time. Additionally, rand
is not cryptographically secure; it is therefore relatively easy to determine its internal state from output.
但是,rand
不是用于此目的的合适的随机函数。它的输出可以很容易地预测,因为它是用当前时间隐式播种的。此外,rand
在加密方面不安全;因此,从输出确定其内部状态相对容易。
Instead, read from /dev/urandom
to get cryptographically random data.
相反,读取/dev/urandom
以获取加密随机数据。
回答by srcspider
base_convert(uniqid('pass', true), 10, 36);
base_convert(uniqid('pass', true), 10, 36);
eg. e0m6ngefmj4
例如。 e0m6ngefmj4
EDIT
编辑
As I've mentioned in comments, the length means that brute force attacks would work better against it then timing attacks so it's not really relevant to worry about "how secure the random generator was." Security, specifically for this use case, needs to complement usability so the above solution is actually good enough for the required problem.
正如我在评论中提到的,长度意味着蛮力攻击比定时攻击更有效,因此担心“随机生成器的安全性”并不重要。安全性,特别是对于此用例,需要补充可用性,因此上述解决方案实际上足以解决所需的问题。
However, just in case you stumbled upon this answer while searching for a secure random string generator (as I assume some people have based on the responses), for something such as generating tokens, here is how a generator of such codes would look like:
但是,以防万一您在搜索安全的随机字符串生成器时偶然发现了这个答案(因为我假设有些人是基于响应的),对于诸如生成令牌之类的事情,以下是此类代码的生成器的外观:
function base64urlEncode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
function secureId($length = 32) {
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes($length);
return rtrim(strtr(base64_encode($bytes), '+/', '0a'), '=');
}
else { // fallback to system bytes
error_log("Missing support for openssl_random_pseudo_bytes");
$pr_bits = '';
$fp = @fopen('/dev/urandom', 'rb');
if ($fp !== false) {
$pr_bits .= @fread($fp, $length);
@fclose($fp);
}
if (strlen($pr_bits) < $length) {
error_log('unable to read /dev/urandom');
throw new \Exception('unable to read /dev/urandom');
}
return base64urlEncode($pr_bits);
}
}