Генерация случайного пароля в php

Я пытаюсь создать случайный пароль в php.

однако я получаю все "a", а возвращаемый тип имеет тип array, и я хотел бы, чтобы это была строка. Есть идеи, как исправить код?

спасибо.

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

22 ответов


предупреждение: rand() не является криптографически безопасным генератором псевдослучайных чисел. Ищите в другом месте создание криптографически безопасной псевдослучайной строки в 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


Я знаю, что вы пытаетесь сгенерировать свой пароль определенным образом, но вы также можете посмотреть на этот метод...

$bytes = openssl_random_pseudo_bytes(2);

$pwd = bin2hex($bytes);

это взято из php.net и он создает строку, которая в два раза длиннее числа, которое вы помещаете в функцию openssl_random_pseudo_bytes. Таким образом, выше будет создан пароль длиной 4 символа.

короче...

$pwd = bin2hex(openssl_random_pseudo_bytes(4));

создаст пароль длиной 8 символов.

обратите внимание, однако, что пароль содержит только цифры 0-9 и маленькие заглавные буквы a-f!


TL; DR:

  • использовать RandomLib.
  • если вы не можете использовать RandomLib, используйте random_int() и данный random_str().
  • если у вас нет random_int() используйте random_compat.

объяснение:

так как вы генерируете пароль, необходимо убедиться, что генерируемый пароль непредсказуем, и единственный способ убедиться, что это свойство присутствует в вашей реализации это использовать криптографически безопасный генератор псевдослучайных чисел (CSPRNG).

требование для CSPRNG может быть ослаблено для общего случая случайных строк, но не тогда, когда речь идет о безопасности.

простой, безопасный и правильный ответ на генерацию паролей в PHP-использовать RandomLib и не изобретайте колесо. Эта библиотека была проверена экспертами по безопасности отрасли, а также себя.

для разработчиков, которые предпочитают изобретать собственное решение, PHP 7.0.0 предоставит random_int() для этой цели. Если вы все еще на PHP 5.х, мы написали PHP 5 polyfill для random_int() таким образом, вы можете использовать новый API до выпуска PHP 7. Используя наш 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.

демо:http://codepad.org/5rHMHwnH

function rand_string( $length ) {

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

}

echo rand_string(8);

С помощью rand_string вы можете определить, сколько символов будет создано.


в одну строку:

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

ваш лучший выбор является библиотека RandomLib от ircmaxell.

пример использования:

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

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

он производит строки, которые более сильно случайны, чем обычные функции случайности, такие как shuffle() и rand() (это то, что вы обычно хотите для конфиденциальной информации, такой как пароли, соли и ключи).


вы хотите strlen($alphabet), а не count постоянной alphabet (эквивалент 'alphabet').

, rand не является подходящей случайной функцией для этой цели. Его выход можно легко предсказать, поскольку он неявно засеян текущим временем. Кроме того, rand не является криптографически безопасным; поэтому относительно легко определить его внутреннее состояние из выходных данных. чтение /dev/urandom для получения криптографически случайные данные.

Я собираюсь написать ответ, потому что некоторые из существующих ответов близки, но один из:

  • меньшее пространство символов, чем вы хотели, так что либо грубое принуждение проще, либо пароль должен быть длиннее для той же энтропии
  • a RNG это не считается криптографически безопасный
  • требование для какой-то сторонней библиотеки, и я подумал, что было бы интересно показать, что может потребоваться для этого себя!--19-->

этот ответ обойдет count/strlen проблема, поскольку безопасность сгенерированного пароля, по крайней мере IMHO, превосходит то, как вы туда добираетесь. Я также собираюсь предположить PHP > 5.3.0.

давайте разбить проблему на составные части, которые являются:

  1. используйте некоторый безопасный источник случайности, чтобы получить случайные данные
  2. используйте эти данные и представляйте их как некоторую строку для печати

для первая часть, 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;
}

для второй части, мы будем использовать base64_encode так как он принимает строку байта и будет производить ряд символов, которые имеют алфавит, очень близкий к тому, который указан в исходном вопросе. Если бы мы не возражали ... --6-->, / и = символы в финальной строке и мы хотим получить результат хотя бы $n символов, мы могли бы просто использовать:

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

на 3/4 фактор обусловлен тем, что кодировка base64 приводит к строке, длина которой по крайней мере на треть больше байтовой строки. Результат будет точным для $n будучи кратным 4 и до 3 символов больше в противном случае. Поскольку дополнительными символами являются преимущественно символы заполнения =, если у нас по какой-то причине было ограничение, что пароль будет точной длиной, затем мы можем обрезать его до нужной длины. Это особенно, потому что для данного $n, все пароли будут заканчиваться одним и тем же числом, так что злоумышленник, имеющий доступ к паролю результата, будет иметь до 2 символов меньше, чтобы угадать.


для дополнительного кредита, если бы мы хотели встретить точную спецификацию, как в вопросе OP, нам пришлось бы сделать немного больше работы. Я собираюсь отказаться от базового конверсионного подхода здесь и иди с быстрым и грязным. Оба должны генерировать больше случайности, чем будет использоваться в результате в любом случае из-за длинного алфавита 62.

для дополнительных символов в результате, мы можем просто выбросить их из результирующей строки. Если мы начнем с 8 байтов в нашей байт-строке, то до 25% символов base64 будут этими "нежелательными" символами, так что просто отбрасывание этих символов приведет к строке не короче, чем требуется OP. Тогда мы можно просто обрезать его, чтобы получить точную длину:

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

если вы создаете более длинные пароли, символ заполнения = формирует все меньшую и меньшую долю промежуточного результата, так что вы можете реализовать более экономичный подход, если осушение пула энтропии, используемого для PRNG, вызывает озабоченность.


это в основном то же самое, что и гораздо проще substr(md5(uniqid()), 0, 8);


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

еще один (только 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


используйте этот простой код для генерации med-strong password 12 length

$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

этот ответ генерирует только шестнадцатеричные символы,0-9,a-f. Для чего-то, что не похоже на 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

это не очень настраиваемый для создания интерфейса для пользователей, но для некоторых целей это нормально. Увеличьте количество символов, чтобы учесть отсутствие специальных символов.


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

немного умнее:

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

проверить здесь.


Я создал более полный и безопасный скрипт пароль. Это создаст комбинацию из двух прописных, двух строчных, двух чисел и двух специальных символов. Всего 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;

Если вы хотите 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);

я собирался попробовать реализовать свой собственный" безопасный "и" случайный " генератор паролей.

Я думал, что было бы интересно и более гибко предоставить length и