在php中生成一个随机密码

我想在PHP中生成一个随机密码。

不过,我得到所有'一个和返回types的数组types,我希望它是一个string。 任何想法如何纠正代码?

谢谢。

function randomPassword() { $alphabet = "abcdefghijklmnopqrstuwxyzABCDEFGHIJKLMNOPQRSTUWXYZ0123456789"; for ($i = 0; $i < 8; $i++) { $n = rand(0, count($alphabet)-1); $pass[$i] = $alphabet[$n]; } return $pass; } 

安全警告rand()不是一个密码安全的伪随机数生成器。 查看其他地方在PHP中生成密码安全的伪随机string 。

试试这个(使用strlen而不是count ,因为count在一个string总是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 } 

演示: http : //codepad.org/UL8k4aYK

我知道你正在试图以特定的方式生成你的密码,但是你也可能想看看这个方法…

 $bytes = openssl_random_pseudo_bytes(2); $pwd = bin2hex($bytes); 

它取自php.net网站,它创build一个string,它是你放在openssl_random_pseudo_bytes函数中的长度的两倍。 所以上面会创build一个4个字符的密码。

简而言之…

 $pwd = bin2hex(openssl_random_pseudo_bytes(4)); 

将创build一个8个字符的密码。

但请注意,密码只包含数字0-9和小写字母af!

TL; DR:

  • 使用RandomLib 。
  • 如果你不能使用RandomLib,使用random_int()和给定的random_str()
  • 如果你没有random_int() ,使用random_compat 。

说明:

由于您正在生成密码 ,因此您需要确保生成的密码是不可预知的,确保此属性的唯一方法是使用密码安全的伪随机数生成器 (CSPRNG)。

对于随机string的一般情况,可以放宽CSPRNG的要求,但不涉及安全性时。

PHP中密码生成的简单,安全和正确的答案是使用RandomLib,而不是重新发明轮子。 这个库已经过行业安全专家和我自己的审核。

对于喜欢创build自己的解决scheme的开发者,PHP 7.0.0将为此提供random_int() 。 如果您仍然使用PHP 5.x,我们为random_int()编写了一个PHP 5的random_int()所以您可以在PHP 7发布之前使用新的API。 使用我们的random_int() 可能比编写自己的实现更安全。

使用一个安全的随机整数发生器,生成一个安全的随机string比饼更容易:

 <?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; } 

微小的代码与2行。

演示: http : //codepad.org/5rHMHwnH

 function rand_string( $length ) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; return substr(str_shuffle($chars),0,$length); } echo rand_string(8); 

用rand_string你可以定义要创build多less字符。

在一行中:

 substr(str_shuffle('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') , 0 , 10 ) 

如果你在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; } 

老答案如下:

 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; } 

你最好的select是ircmaxellRandomLib库

用法示例:

 $factory = new RandomLib\Factory; $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM)); $passwordLength = 8; // Or more $randomPassword = $generator->generateString($passwordLength); 

它生成的string比随机函数shuffle()rand() (这是密码,盐和密钥等敏感信息所需的一般随机函数shuffle()更为随机。

你想strlen($alphabet) ,而不是常数alphabet (相当于'alphabet' )的count

但是, rand不是一个合适的随机函数。 它的输出可以很容易地预测,因为它是隐含在当前时间播种。 另外, rand不是安全的, 因此从输出中确定其内部状态相对容易。

相反,从/dev/urandom读取密码随机数据。

我打算发表一个答案,因为一些现有的答案是接近的,但有一个:

  • 一个比你想要的更小的字符空间,这样或者暴力破解更容易,或者密码对于相同的熵必须更长
  • 一个不被认为是密码安全的RNG
  • 一些第三方图书馆的要求,我认为这可能是有趣的,以显示自己可能需要做什么

这个答案将绕过count/strlen问题,因为生成的密码的安全性,至less恕我直言,超越你如何到达那里。 我也将假设PHP> 5.3.0。

让我们把问题分解成以下几个组成部分:

  1. 使用一些安全的随机来源来获得随机数据
  2. 使用该数据并将其表示为一些可打印的string

对于第一部分,PHP> 5.3.0提供了openssl_random_pseudo_bytes函数。 请注意,尽pipe大多数系统使用密码强的algorithm,但您必须检查,以便使用包装器:

 /** * @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; } 

对于第二部分,我们将使用base64_encode因为它需要一个字节string,并会产生一系列字母,其字母非常接近原始问题中指定的字母。 如果我们不介意+/=字符出现在最后一个string中,并且我们想要一个至less有$n字符的结果,我们可以简单地使用:

 base64_encode(strong_random_bytes(intval(ceil($n * 3 / 4)))); 

3/4因子是由于base64编码导致长度至less比字节串大三分之一的string。 结果将是精确的, $n是4的倍数,否则长达3个字符。 由于额外的字符主要是填充字符= ,如果我们由于某种原因有一个约束,即密码是一个确切的长度,那么我们可以截断它到我们想要的长度。 特别是因为对于一个给定的$n ,所有的密码都会以相同的密码结束,这样一个攻击者可以使用一个结果密码来猜测。


对于额外的信用,如果我们想要在OP的问题中满足确切的规格,那么我们将不得不做更多的工作。 我要放弃这里的基本转换方法,并且快速和肮脏地进行。 由于62字母长的字母,两者都需要产生比随机结果更多的随机性。

对于结果中的额外字符,我们可以简单地从结果string中丢弃它们。 如果我们以字节串中的8个字节开始,那么大约25%的base64字符将成为这些“不受欢迎的”字符,因此,简单地丢弃这些字符会导致string不会比OP要的短。 然后,我们可以简单地截断它到确切的长度:

 $dirty_pass = base64_encode(strong_random_bytes(8))); $pass = substr(str_replace(['/', '+', '='], ['', '', ''], $dirty_pass, 0, 8); 

如果生成更长的密码,则填充字符=形成中间结果的越来越小的比例,因此,如果耗尽用于PRNG的熵池是一个问题,则可以实施更精简的方法。

这与简单得多的substr(md5(uniqid()), 0, 8);基本相同substr(md5(uniqid()), 0, 8);

base_convert(uniqid('pass', true), 10, 36);

例如。 e0m6ngefmj4

编辑

正如我在评论中提到的那样,长度意味着蛮力攻击会更好地抵抗攻击,然后计时攻击,因此担心“随机发生器有多安全”并不重要。 安全,特别是对于这个用例,需要补充可用性,所以上述解决scheme对于所需的问题来说足够好。

但是,为了防止在search安全的随机string生成器(如我假设有些人基于响应)时偶然发现了这个答案,对于诸如生成令牌的东西,下面是这样的代码的生成器如何看起来像:

 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); } } 

另一个(仅限Linux)

 function randompassword() { $fp = fopen ("/dev/urandom", 'r'); if (!$fp) { die ("Can't access /dev/urandom to get random data. Aborting."); } $random = fread ($fp, 1024); # 1024 bytes should be enough fclose ($fp); return trim (base64_encode ( md5 ($random, true)), "="); } 

试试大写字母,小写字母,数字和特殊字符

 function generatePassword($_len) { $_alphaSmall = 'abcdefghijklmnopqrstuvwxyz'; // small letters $_alphaCaps = strtoupper($_alphaSmall); // CAPITAL LETTERS $_numerics = '1234567890'; // numerics $_specialChars = '`~!@#$%^&*()-_=+]}[{;:,<.>/?\'"\|'; // Special Characters $_container = $_alphaSmall.$_alphaCaps.$_numerics.$_specialChars; // Contains all characters $password = ''; // will contain the desired pass for($i = 0; $i < $_len; $i++) { // Loop till the length mentioned $_rand = rand(0, strlen($_container) - 1); // Get Randomized Length $password .= substr($_container, $_rand, 1); // returns part of the string [ high tensile strength ;) ] } return $password; // Returns the generated Pass } 

假设我们需要10位数字通行证

 echo generatePassword(10); 

输出示例:

,IZCQ_IV \ 7

@wlqsfhT(d

1!8 + 1 \ 4 @ UD

使用这个简单的代码来生成中等强度的密码长度

 $password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789'; $password = substr(str_shuffle($password_string), 0, 12); 

快一个。 简单,干净和一致的格式,如果这是你想要的

 $pw = chr(mt_rand(97,122)).mt_rand(0,9).chr(mt_rand(97,122)).mt_rand(10,99).chr(mt_rand(97,122)).mt_rand(100,999); 

这是基于这个页面上的另一个答案, https://stackoverflow.com/a/21498316/525649

这个答案只产生hex字符, 0-9,af 。 对于看起来不像hex的东西,试试这个:

 str_shuffle( rtrim( base64_encode(bin2hex(openssl_random_pseudo_bytes(5))), '=' ). strtoupper(bin2hex(openssl_random_pseudo_bytes(7))). bin2hex(openssl_random_pseudo_bytes(13)) ) 
  • base64_encode返回更广泛的字母数字字符
  • rtrim删除了=有时候

例子:

  • 32eFVfGDg891Be5e7293e54z1D23110M3ZU3FMjb30Z9a740Ej0jz4
  • b280R72b48eOm77a25YCj093DE5d9549Gc73Jg8TdD9Z0Nj4b98760
  • 051b33654C0Eg201cfW0e6NA4b9614ze8D2FN49E12Y0zY557aUCb8
  • y67Q86ffd83G0z00M0Z152f7O2ADcY313gD7a774fc5FF069zdb5b7

这对于为用户创build一个界面不是很好的configuration,但是对于某些目的来说没关系。 增加字符的数量来说明缺less特殊字符的情况。

  1. 用这个代码创build一个文件。
  2. 像在评论中那样调用它。

     <?php /** * @usage : * include_once($path . '/Password.php'); * $Password = new Password; * $pwd = $Password->createPassword(10); * return $pwd; * */ class Password { public function createPassword($length = 15) { $response = []; $response['pwd'] = $this->generate($length); $response['hashPwd'] = $this->hashPwd( $response['pwd'] ); return $response; } private function generate($length = 15) { $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(){}/?,><"; return substr(str_shuffle($chars),0,$length); } private function hashPwd($pwd) { return hash('sha256', $pwd); } } ?> 

我创build了一个更全面和安全的密码脚本。 这将创build两个大写,两个小写,两个数字和两个特殊字符的组合。 共8个字符。

 $char = [range('A','Z'),range('a','z'),range(0,9),['*','%','$','#','@','!','+','?','.']]; $pw = ''; for($a = 0; $a < count($char); $a++) { $randomkeys = array_rand($char[$a], 2); $pw .= $char[$a][$randomkeys[0]].$char[$a][$randomkeys[1]]; } $userPassword = str_shuffle($pw); 
 <?php // We can generate without large code.. $length = 8; $chars = array_merge(range(0,9), range('a','z'),range('A','Z'),['!','@','#','$','%','&','*','?']); //$chars = array_merge(range(0,1), range('A','Z')); shuffle($chars); $code = implode(array_slice($chars, 0, $length)); $arr = array($code); $password = implode("",$arr); echo $password; 

我一直在尝试实现我自己的“安全”和“随机”密码生成器。

我认为给函数提供一个lengthtype参数会很有趣也很灵活。

这是一个函数,执行一些检查,以确保length不是太短或长(也允许可变长度)。 它还允许在type参数中select密码字符集。

如果lengthtype是无效的,并且使用比rand()更“随机”的PHP mt_rand()函数,则返回null

 <?php /** * Generates a random password with the given length and of the given type. * * @param int $length * @param string $type * @return string | null */ function random_password($length=8, $type='alpha_numeric') { if ($length < 1 || $length > 1024) return null; $lower = 'abcdefghijklmnopqrstuvwxy'; $upper = strtoupper($lower); $numbers = '1234567890'; $dash = '-'; $underscore = '_'; $symbols = '`~!@#$%^&*()+=[]\\{}|:";\'<>?,./'; switch ($type) { case 'lower': $chars = $lower; break; case 'upper': $chars = $upper; break; case 'numeric': $chars = $numbers; break; case 'alpha': $chars = $lower . $upper; break; case 'symbol': $chars = $symbols . $dash . $underscore; break; case 'alpha_numeric': $chars = $lower . $upper . $numbers; break; case 'alpha_numeric_dash': $chars = $lower . $upper . $numbers . $dash; break; case 'alpha_numeric_underscore': $chars = $lower . $upper . $numbers . $underscore; break; case 'alpha_numeric_dash_underscore': $chars = $lower . $upper . $numbers . $underscore . $dash; break; case 'all': $chars = $lower . $upper . $numbers . $underscore . $dash . $symbols; break; default: return null; } $min = 0; $max = strlen($chars) - 1; $password = ''; for ($i = 0; $i < $length; $i++) { $random = mt_rand($min, $max); $char = substr($chars, $random, 1); $password .= $char; } return $password; }