Generating a random password in php

2019-01-02 19:09发布

I am trying to generate a random password in 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?

Thanks.

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

22条回答
泛滥B
2楼-- · 2019-01-02 19:53

This is based off another answer on this page, https://stackoverflow.com/a/21498316/525649

This answer generates just hex characters, 0-9,a-f. For something that doesn't look like hex, try this:

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 returns a wider spread of alphanumeric chars
  • rtrim removes the = sometimes at the end

Examples:

  • 32eFVfGDg891Be5e7293e54z1D23110M3ZU3FMjb30Z9a740Ej0jz4
  • b280R72b48eOm77a25YCj093DE5d9549Gc73Jg8TdD9Z0Nj4b98760
  • 051b33654C0Eg201cfW0e6NA4b9614ze8D2FN49E12Y0zY557aUCb8
  • y67Q86ffd83G0z00M0Z152f7O2ADcY313gD7a774fc5FF069zdb5b7

This isn't very configurable for creating an interface for users, but for some purposes that's okay. Increase the number of chars to account for the lack of special characters.

查看更多
回忆,回不去的记忆
3楼-- · 2019-01-02 19:54

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

eg. 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);
    }
}
查看更多
骚的不知所云
4楼-- · 2019-01-02 19:57

If you are on PHP7 you could use the random_int() function:

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;
}
查看更多
深知你不懂我心
5楼-- · 2019-01-02 19:58

TL;DR:

  • Use RandomLib.
  • If you can't use RandomLib, use random_int() and the given random_str().
  • If you don't have random_int(), use 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).

The requirement for a CSPRNG can be relaxed for the general case of random strings, but not when security is involved.

The simple, secure, and correct answer to password generation in PHP is to use RandomLib and don't reinvent the wheel. This library has been audited by industry security experts, as well as myself.

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 probably safer than writing your own implementation.

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;
}
查看更多
弹指情弦暗扣
6楼-- · 2019-01-02 20:01

You want strlen($alphabet), not count of the constant alphabet (equivalent to '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.

Instead, read from /dev/urandom to get cryptographically random data.

查看更多
唯独是你
7楼-- · 2019-01-02 20:01

Another one (linux only)

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)), "=");
}
查看更多
登录 后发表回答