在PHP中生成随机密码

234

我试图在PHP中生成随机密码。

然而,我得到的都是 'a',返回类型是数组类型,而我想要它是字符串类型。有什么办法可以纠正代码吗?

谢谢。

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

9
所有答案都没有使用安全的随机数生成器,而你需要它来生成密码。 - Scott Arciszewski
4
访客应该从一个可以适当更新的来源获取可能与安全有关的信息,而不是一个关闭了新回答的问题。我正在删除重复问题的答案,这样访客就会读到开放问题的答案。如果这个问题被重新打开,答案将被恢复。 - Jeremy
6
在这个问题中,没有明确说明需要使用“密码学安全的”密码。对于一些人来说,使用“/dev/random”的答案已经足够了,因为问题并没有要求一个“安全”的密码(也不应该被编辑以包含它,因为那样会改变原问题的意思)。虽然我非常支持安全性,但我认为这种方式并没有充分考虑。就像使用“mysql_”一样,这些答案仍然有效,但应该标记为不安全。也许这是SO需要包含的额外软件--能够警告*不安全的代码的能力? - Jimbo
6
@JeremyBanks 你能否恢复这个问题的答案?仅仅因为它是一个重复问题并不意味着答案是错误的(我不小心投票重新打开了,我同意这是一个重复问题)。删除答案没有任何意义,考虑将此问题删除并将答案迁移到其他问题上(我以前见过这样做)。 - Naftali
7
如果你想让某个东西不再重新开放,那么锁定它。否则99%的人都会重新开放它,并制造一堆麻烦。就我个人而言,我完全不同意这样随意删除得分高的答案,但也不能与你为此而争论。 - Shadow The Spring Wizard
显示剩余9条评论
32个回答

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

1
PS - 这是 PHP - 只是使用 \ 来表示全局命名空间。 - Bob Gregor
除非 uniqid 是加密安全的,否则请改用 rand():base_convert(rand(78364164096, 2821109907455), 10, 36); - Benubird
8
@Benubird 根据 PHP 手册,rand() 也不是加密安全的。手册建议使用 openssl_random_pseudo_bytes()。 - willbradley
对于大多数用例,特别是攻击者无法获得确切时间的情况下,这样做是完全可以的,并产生一种相对人类友好的“临时”密码。如果我们把这个问题推向极端,长度比生成随机数所用的函数更加麻烦。 - srcspider
我已经添加了一个生成完全安全字符串的示例,供有兴趣的人参考;但是强烈不建议在为用户生成临时密码时使用此方法。即使使用了安全版本,长度问题仍然存在。 - srcspider

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)), "=");
}

2
读取1024字节以压缩熵为128位的加密哈希有些浪费。此外,fread()默认缓冲区大小为8192字节,因此您始终会从/dev/urandom读取这么多数据。这在Windows上也不起作用。不过,使用CSPRNG值得赞扬。 - Scott Arciszewski

7

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

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


3
“rand”函数实际上并不具备加密安全性,因此使用它生成密码可能会带来相当大的风险。 - jeteon

5
使用以下简单代码生成12位中强度密码
$password_string = '!@#$%*&abcdefghijklmnpqrstuwxyzABCDEFGHJKLMNPQRSTUWXYZ23456789';
$password = substr(str_shuffle($password_string), 0, 12);

1
这实际上是非常错误的。它实际上只使用了字母表中的每个字符一次,因此严重缩小了所有可能值的空间(与破解相关)。 - Radoslav Bodó

4

以下是我为选项列表做出的贡献。

该函数确保符合密码策略要求。

  function password_generate($length=8, $min_lowercases=1, $min_uppercases=1, $min_numbers=1, $min_specials=0) {

    $lowercases = 'abcdefghijklmnopqrstuvwxyz';
    $uppercases = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $numbers = '0123456789';
    $specials = '!#%&/(){}[]+-';

    $absolutes = '';
    if ($min_lowercases && !is_bool($min_lowercases)) $absolutes .= substr(str_shuffle(str_repeat($lowercases, $min_lowercases)), 0, $min_lowercases);
    if ($min_uppercases && !is_bool($min_uppercases)) $absolutes .= substr(str_shuffle(str_repeat($uppercases, $min_uppercases)), 0, $min_uppercases);
    if ($min_numbers && !is_bool($min_numbers)) $absolutes .= substr(str_shuffle(str_repeat($numbers, $min_numbers)), 0, $min_numbers);
    if ($min_specials && !is_bool($min_specials)) $absolutes .= substr(str_shuffle(str_repeat($specials, $min_specials)), 0, $min_specials);

    $remaining = $length - strlen($absolutes);

    $characters = '';
    if ($min_lowercases !== false) $characters .= substr(str_shuffle(str_repeat($lowercases, $remaining)), 0, $remaining);
    if ($min_uppercases !== false) $characters .= substr(str_shuffle(str_repeat($uppercases, $remaining)), 0, $remaining);
    if ($min_numbers !== false) $characters .= substr(str_shuffle(str_repeat($numbers, $remaining)), 0, $remaining);
    if ($min_specials !== false) $characters .= substr(str_shuffle(str_repeat($specials, $remaining)), 0, $remaining);

    $password = str_shuffle($absolutes . substr($characters, 0, $remaining));

    return $password;
  }

$min_*参数可以有以下值:

  • 1-999 = 必填
  • true = 可选
  • false = 禁用

可使用示例如下:

echo password_generate(8); // Outputs a random 8 characters long password

要求密码为10个字符,至少包含每组字符集中的2个字符:

echo password_generate(10, 2, 2, 2, 2);

只输出6个随机数

echo password_generate(6, false, false, true, false);

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

2

这是基于本页面上另一个回答的,https://dev59.com/5W025IYBdhLWcg3wST2Q#21498316

这个答案只生成十六进制字符 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

这对于为用户创建界面来说并不是很可配置,但对于某些目的来说,这也是可以接受的。增加字符数以弥补缺乏特殊字符的影响。


2
  1. Create a file with this code in it.
  2. Call it like in the comments.

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

2
一个简单的代码应该像这样:
function generatePassword($len){
    $az = range("a","z");
    $AZ = range("A","Z");
    $num = range(0,9);
    $password = array_merge($az,$AZ,$num);
    return substr(str_shuffle(implode("",$password)),0, $len);
}
// testing 
$generate = range(8,32);
foreach($generate as $g){
    print "Len:{$g} = " . generatePassword($g)."\n";
}

输出:

Len:8 = G5uFhPKS
Len:9 = aU9x2NjvI
Len:10 = lJE9kxy3oD
Len:11 = tVh2CmpMdHW
Len:12 = ToXYHCPb58Ar
Len:13 = KIFVoLg5NdDzX
Len:14 = eFUabML28tXhf0
Len:15 = iegDCQcIMaxH0ST
Len:16 = sRvDmPo5IkaMqNO0
Len:17 = T5rwVDs6XGAqSU9KN
Len:18 = QwROWAfh1lpoCSaX0H
Len:19 = HP0trD4B9SQeUkNuAGV
Len:20 = P9Fdwqmu782ARHDiKGZM
Len:21 = 3Gxia9LPmCZM68dwe4YOf
Len:22 = ywFjuA2GDg0Oz8LVnCI94M
Len:23 = 16MiEVUgqPRueahlyvJfBz5
Len:24 = sPt0H9NSu5KrJTYeMXbOFgi7
Len:25 = QFKGTypaZlsMRnHPgNbVfIwxm
Len:26 = hbyJXtV81AEuMazS4GdFTINBUg
Len:27 = H3AiD95S4Z8xwMrz2L71GqUunaW
Len:28 = m8W2geIiO7Phc3H5Kyr1XCAs09Dv
Len:29 = MusNfYgOWnbrI62twRBvj38XEcDdi
Len:30 = VgNeILaRT2wvb4J7hzCMSHsquUBtnA
Len:31 = nhUvCxgOS94dsYjzBtcaTou1WIArMQP
Len:32 = AFSVQqCijuPMp0cGJNdDtzYX78erKB9w

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接