在php中生成随机密码

时间:2011-05-23 19:29:29

标签: php security random passwords

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

但是我得到所有'a'并且返回类型是数组类型,我希望它是一个字符串。关于如何纠正代码的任何想法?

感谢。

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

29 个答案:

答案 0 :(得分:235)

  

安全警告rand()不是加密安全的伪随机数生成器。在其他地方寻找generating a cryptographically secure pseudorandom string in PHP

尝试此操作(使用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
}

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

答案 1 :(得分:106)

TL; DR:

  • 使用random_int()和下面的给定random_str()
  • 如果您没有random_int(),请使用random_compat

说明:

由于您要生成密码,因此您需要确保生成的密码不可预测,并且确保实现中存在此属性的唯一方法是使用{{3} (CSPRNG)。

对于随机字符串的一般情况,可以放宽对CSPRNG的要求,但在涉及安全性时则不能。

在PHP中生成密码的简单,安全和正确的答案是使用cryptographically secure pseudorandom number generator并且不要重新发明轮子。该图书馆已经过行业安全专家和我自己的审核。

对于喜欢发明自己的解决方案的开发人员,PHP 7.0.0将为此提供RandomLib。如果你还在PHP 5.x上,我们写了一个random_int(),这样你就可以在PHP 7发布之前使用新的API。使用我们的random_int() polyfill 可能比编写自己的实现更安全。

使用安全的随机整数生成器,生成安全的随机字符串比使用派对更容易:

<?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 :(得分:103)

我知道您正在尝试以特定方式生成密码,但您可能也想查看此方法...

$bytes = openssl_random_pseudo_bytes(2);

$pwd = bin2hex($bytes);

它取自php.net网站,它创建的字符串长度是op​​enssl_random_pseudo_bytes函数中的两倍。所以上面会创建一个4个字符的密码。

简而言之......

$pwd = bin2hex(openssl_random_pseudo_bytes(4));

会创建长度为8个字符的密码。

但请注意,密码仅包含数字0-9和小写字母a-f!

答案 3 :(得分:52)

2行的小代码。

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

function rand_string( $length ) {

    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return substr(str_shuffle($chars),0,$length);

}

echo rand_string(8);
  

使用rand_string可以定义要创建的字符数。

答案 4 :(得分:36)

如果您使用的是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;
}

答案 5 :(得分:36)

在一行中:

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

答案 6 :(得分:26)

最好的选择是 RandomLib library by ircmaxell

用法示例:

$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));

$passwordLength = 8; // Or more
$randomPassword = $generator->generateString($passwordLength);

它产生的字符串比正常随机函数(如shuffle()rand()更强随机(这是您通常想要的密码,盐和密钥等敏感信息)。

答案 7 :(得分:14)

我将发布一个答案,因为现有的一些答案很接近,但却有以下答案之一:

  • 比您想要的更小的字符空间,以便强制执行更容易,或者密码对于相同的熵必须更长
  • RNG,不被认为是加密安全的
  • 对某些第三方图书馆的要求,我认为展示自己可能需要做些什么可能很有意思

这个答案将绕过count/strlen问题,因为生成的密码的安全性,至少是恕我直言,超越了你到达那里的方式。我也将假设PHP&gt; 5.3.0。

让我们将问题分解为以下组成部分:

  1. 使用一些安全的随机源来获取随机数据
  2. 使用该数据并将其表示为一些可打印的字符串
  3. 对于第一部分,PHP&gt; 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;
    }
    

    对于第二部分,我们将使用base64_encode,因为它需要一个字节字符串,并且会生成一系列字符,这些字符的字母表与原始问题中指定的字符非常接近。如果我们不介意+/=字符出现在最终字符串中,并且我们希望结果至少为$n个字符,我们可以简单地使用方法:

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

    3/4因素是由于base64编码导致字符串的长度至少比字节字符串大三分之一。结果将精确地$n是4的倍数,否则最多3个字符。由于额外的字符主要是填充字符=,如果我们由于某种原因有一个约束密码是一个确切的长度,那么我们可以将它截断到我们想要的长度。这尤其是因为对于给定的$n,所有密码都以相同数量的密码结束,因此有权访问结果密码的攻击者最多可以猜测2个字符。

    要获得额外的功劳,如果我们想要满足OP问题中的确切规范,那么我们将不得不做更多的工作。我将在这里放弃基本转换方法,然后选择快速而肮脏的方法。由于62条长字母表,两者都需要产生比结果中使用的更多的随机性。

    对于结果中的额外字符,我们可以简单地从结果字符串中丢弃它们。如果我们在字节字符串中以8个字节开始,那么最多约25%的base64字符将是这些&#34;不合需要的&#34;字符,因此简单地丢弃这些字符会导致字符串不短于OP所需的字符串。然后我们可以简单地截断它以达到确切的长度:

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

    如果生成更长的密码,填充字符=会形成较小和较小比例的中间结果,这样您就可以实现更精简的方法,如果排除用于PRNG的熵池是一个问题。< / p>

答案 8 :(得分:14)

您想要strlen($alphabet),而不是常量count的{​​{1}}(相当于alphabet)。

但是,'alphabet'不是用于此目的的合适随机函数。它的输出很容易预测,因为它隐含在当前时间播种。此外,rand不具有加密安全性;因此,从输出中确定其内部状态相对容易。

而是从rand读取以获取加密随机数据。

答案 9 :(得分:11)

这与更简单的substr(md5(uniqid()), 0, 8);

基本相同

答案 10 :(得分:11)

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

例如。 e0m6ngefmj4

修改

正如我在评论中提到的那样,长度意味着暴力攻击会更好地对抗它然后进行定时攻击,所以担心“随机生成器有多安全”并不是真的有意义。安全性,特别是针对此用例,需要补充可用性,因此上述解决方案实际上足以满足所需的问题。

但是,如果你在搜索安全的随机字符串生成器时偶然发现了这个答案(因为我假设有些人基于响应),对于诸如生成令牌之类的东西,这里是这样的代码的生成器将如何看起来像:

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

答案 11 :(得分:9)

另一个(仅限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)), "=");
}

答案 12 :(得分:8)

更聪明一点:

function strand($length){
  if($length > 0)
    return chr(rand(33, 126)) . strand($length - 1);
}

检查here

答案 13 :(得分:6)

使用此简单代码生成医学密码12长度

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

答案 14 :(得分:5)

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

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

答案 15 :(得分:3)

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

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

答案 16 :(得分:3)

  1. 使用此代码创建一个文件。
  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);
        }
    
    }
    
    ?>
    

答案 17 :(得分:3)

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

此答案仅生成十六进制字符0-9,a-f。对于看起来不像十六进制的东西,试试这个:

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

这对于为用户创建界面不是很容易配置,但出于某些目的,这没关系。增加字符数以解释缺少特殊字符的问题。

答案 18 :(得分:2)

我创建了一个更全面,更安全的密码脚本。这将创建两个大写,两个小写,两个数字和两个特殊字符的组合。共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);

答案 19 :(得分:1)

此功能将根据参数中的规则生成密码

function random_password( $length = 8, $characters = true, $numbers = true, $case_sensitive = true, $hash = true ) {

    $password = '';

    if($characters)
    {
        $charLength = $length;
        if($numbers) $charLength-=2;
        if($case_sensitive) $charLength-=2;
        if($hash) $charLength-=2;
        $chars = "abcdefghijklmnopqrstuvwxyz";
        $password.= substr( str_shuffle( $chars ), 0, $charLength );
    }

    if($numbers)
    {
        $numbersLength = $length;
        if($characters) $numbersLength-=2;
        if($case_sensitive) $numbersLength-=2;
        if($hash) $numbersLength-=2;
        $chars = "0123456789";
        $password.= substr( str_shuffle( $chars ), 0, $numbersLength );
    }

    if($case_sensitive)
    {
        $UpperCaseLength = $length;
        if($characters) $UpperCaseLength-=2;
        if($numbers) $UpperCaseLength-=2;
        if($hash) $UpperCaseLength-=2;
        $chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $password.= substr( str_shuffle( $chars ), 0, $UpperCaseLength );
    }

    if($hash)
    {
        $hashLength = $length;
        if($characters) $hashLength-=2;
        if($numbers) $hashLength-=2;
        if($case_sensitive) $hashLength-=2;
        $chars = "!@#$%^&*()_-=+;:,.?";
        $password.= substr( str_shuffle( $chars ), 0, $hashLength );
    }

    $password = str_shuffle( $password );
    return $password;
}

答案 20 :(得分:1)

我的答案与上述类似,但我删除了元音1和0,字母i,j,I,l,O,o,Q,q,X,x,Y,y,W, w。原因是:第一个很容易混合(例如l和1,具体取决于字体),而其余的(以Q开头)是因为它们在我的语言中不存在,因此它们可能有点奇怪超级用户。字符串仍然足够长。另外,我知道使用一些特殊的标志是理想的,但是它们也与某些最终用户不相处。

struct ContentView: View {

    var body: some View {
            ScrollView(.vertical, showsIndicators: false){
                 VStack {
                     Text("Content View text")
                     Image("contentviewimage")
                     ForEach((1...10), id: \.self) {
                        user in UserCard()
                     }
                 }
           }
    }
}


struct UserView: View {

    var body: some View {
        NavigationView {
                 VStack {
                     Image("bob")
                     Text("Hello my name is bob")
                     NavigationLink(
                        destination: BobView()){
                            Text("Click me to navigate").font(.system(size: 20))
                        }
                 }
            }
        }
    }
}

struct BobView: View{
  var body: some View{
     VStack{Text("bob view")}
   }
}

此外,通过这种方式,我们避免重复相同的字母和数字(不包括大小写匹配)

答案 21 :(得分:0)

//define a function. It is only 3 lines!   
function generateRandomPassword($length = 5){
    $chars = "123456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ";
    return substr(str_shuffle($chars),0,$length);
}

//usage
echo generateRandomPassword(5); //random password legth: 5
echo generateRandomPassword(6); //random password legth: 6
echo generateRandomPassword(7); //random password legth: 7

答案 22 :(得分:0)

生成长度为8的强密码,其中至少包含一个小写字母,一个大写字母,一位数字和一个特殊字符。您也可以在代码中更改长度。     

function checkForCharacterCondition($string) {
    return (bool) preg_match('/(?=.*([A-Z]))(?=.*([a-z]))(?=.*([0-9]))(?=.*([~`\!@#\$%\^&\*\(\)_\{\}\[\]]))/', $string);
}

$j = 1;

function generate_pass() {
    global $j;
    $allowedCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_{}[]';
    $pass = '';
    $length = 8;
    $max = mb_strlen($allowedCharacters, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pass .= $allowedCharacters[random_int(0, $max)];
    }

    if (checkForCharacterCondition($pass)){
        return '<br><strong>Selected password: </strong>'.$pass;
    }else{
        echo 'Iteration '.$j.':  <strong>'.$pass.'</strong>  Rejected<br>';
        $j++;
        return generate_pass();
    }

}

echo generate_pass();

答案 23 :(得分:0)

这是我随意使用的普通密码生成助手。

确保密码包含数字,大写和小写字母以及至少3个特殊字符。

密码的长度在11到30之间。

function plainPassword(): string
{
    $numbers = array_rand(range(0, 9), rand(3, 9));
    $uppercase = array_rand(array_flip(range('A', 'Z')), rand(2, 8));
    $lowercase = array_rand(array_flip(range('a', 'z')), rand(3, 8));
    $special = array_rand(array_flip(['@', '#', '$', '!', '%', '*', '?', '&']), rand(3, 5));

    $password = array_merge(
        $numbers,
        $uppercase,
        $lowercase,
        $special
    );

    shuffle($password);

    return implode($password);
}

答案 24 :(得分:0)

didChangeSize old: (810.0, 1080.0) new: (1080.0, 810.0)
didSetSize: (1080.0, 810.0)
didChangeSize old: (810.0, 1080.0) new: (1080.0, 810.0)

答案 25 :(得分:0)

生成随机密码串

function generate_randompassword($passlength = 8){
    $alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#%^*>\$@?/[]=+';
    $pass = array(); //remember to declare $pass as an array
    $alphaLength = strlen($alphabet) - 1; //put the length -1 in cache
    for ($i = 0; $i < $passlength; $i++) {
        $n = rand(0, $alphaLength);
        $pass[] = $alphabet[$n];
    }
    return implode($pass); //turn the array into a string
}

答案 26 :(得分:-1)

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

答案 27 :(得分:-1)

如果要使用8个字符(1个大写字母和1个数字)。

  $p_lc_letters = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 6); // Generate 6 lowercase letters
  $p_uc_letters = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 1); // Generate 1 uppercase letter
  $p_numbers = substr(str_shuffle('0123456789'), 0, 1); // Generate 1 number

  echo $password = substr(str_shuffle($p_lc_letters.''.$p_uc_letters.''.$p_numbers), 0, 8);

答案 28 :(得分:-2)

我的意思是尝试实施我自己的&#34;安全&#34;和&#34;随机&#34;密码生成器。

我认为为函数提供lengthtype参数会更有趣,更灵活。

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

如果nulllength无效,则返回type,并使用PHP&#39; mt_rand()函数,该函数更多&#34;随机&#34;比rand()

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