Подтвердить что ты не робот

Каков наилучший способ генерации случайного ключа в PHP?

Я хочу создать функцию многократного использования, которая будет генерировать случайный ключ с печатными символами ACSII выбранной длины (от 2 до 1000+). Я думаю, что печатные символы ASCII будут 33-126. Они не обязательно должны быть полностью уникальными, просто уникальными, если они сгенерированы на той же миллисекунде (так что uniqid() не будет работать).

Я думаю, что комбинация chr() и mt_rand() может работать.

Это путь, или что-то еще лучший метод?

Изменить: uniqid() также не будет работать, потому что у него нет параметра длины, это просто то, что дает PHP.

Моя идея. Это то, что я придумал:

function GenerateKey($length = 16) {
    $key = '';

    for($i = 0; $i < $length; $i ++) {
        $key .= chr(mt_rand(33, 126));
    }

    return $key;
}

Есть ли проблемы с этим?

Другое Редактировать:. Большинство других вопросов касаются генерации пароля. Я хочу более широкий спектр персонажей, и меня не волнует 1 vs l. Я хочу, чтобы максимальное количество возможных ключей было возможным.

Примечание: сгенерированный ключ необязательно должен быть криптографически защищен.

4b9b3361

Ответ 1

Обновление (12/2015): для PHP 7.0 вы должны использовать random_int() вместо mt_rand, поскольку он обеспечивает "криптографически безопасные значения"

Лично мне нравится использовать sha1(microtime(true).mt_rand(10000,90000)), но вы ищете больше настраиваемого подхода, поэтому попробуйте эту функцию (которая является модификацией вашего запроса этого ответа):

function rand_char($length) {
  $random = '';
  for ($i = 0; $i < $length; $i++) {
    $random .= chr(mt_rand(33, 126));
  }
  return $random;
}

Тем не менее, это, вероятно, будет значительно медленнее, чем uniqid(), md5() или sha1().

Изменить: Похоже, вы добрались до него сначала, извините.: D

Изменить 2: Я решил сделать небольшой тест на моей машине Debian с PHP 5 и eAccelerator (извините длинный код):

function rand_char($length) {
  $random = '';
  for ($i = 0; $i < $length; $i++) {
    $random .= chr(mt_rand(33, 126));
  }
  return $random;
}

function rand_sha1($length) {
  $max = ceil($length / 40);
  $random = '';
  for ($i = 0; $i < $max; $i ++) {
    $random .= sha1(microtime(true).mt_rand(10000,90000));
  }
  return substr($random, 0, $length);
}

function rand_md5($length) {
  $max = ceil($length / 32);
  $random = '';
  for ($i = 0; $i < $max; $i ++) {
    $random .= md5(microtime(true).mt_rand(10000,90000));
  }
  return substr($random, 0, $length);
}

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_char(1000);

echo "Rand:\t".(microtime(true) - $a)."\n";

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_sha1(1000);

echo "SHA-1:\t".(microtime(true) - $a)."\n";

$a = microtime(true);
for ($x = 0; $x < 1000; $x++)
  $temp = rand_md5(1000);

echo "MD5:\t".(microtime(true) - $a)."\n";

Результаты:

Rand:   2.09621596336
SHA-1:  0.611464977264
MD5:    0.618473052979

Итак, мое предложение, если вы хотите скорость (но не полную кодировку), должно придерживаться MD5, SHA-1 или Uniqid (которые я еще не тестировал).

Ответ 2

Ни один из ответов здесь не достаточен, если вам нужна криптографическая сила случайности (есть ли определенный злоумышленник, пытающийся угадать, каковы ваши случайные ключи?). Хеширование времени небезопасно, злоумышленник может значительно ускорить поиск, угадывая время, в течение которого они думают, что ваш сервер сгенерировал ключ, и легко просматривать все миллисекунды за определенный год, даже на товарном ноутбуке (это 35 битное пространство поиска). Кроме того, опасно опасно предположение просто запустить результаты uniqid() или другого слабого случайного источника через хэш-функцию, чтобы "развернуть его" - это не делает поиск злоумышленника более сложным, если они узнают, что вы это сделали.

Если вам действительно нужна криптоуровневая безопасность, вы должны прочитать /dev/random, следующий код должен работать для вас в любой POSIX-совместимой системе (ничего, кроме Windows):

#Generate a random key from /dev/random
function get_key($bit_length = 128){
    $fp = @fopen('/dev/random','rb');
    if ($fp !== FALSE) {
        $key = substr(base64_encode(@fread($fp,($bit_length + 7) / 8)), 0, (($bit_length + 5) / 6)  - 2);
        @fclose($fp);
        return $key;
    }
    return null;
}

Если вам требуется немного больше скорости, вы можете читать вместо этого "dev/urandom".

Ответ 3

Вы все еще можете использовать uniqid(), просто выполните некоторую дополнительную обработку, чтобы расширить ее значение до количества символов, которые вам нужны.

Например, чтобы развернуть его до 32 символов, вы можете сделать

$id = md5(uniqid());

Чтобы развернуть его до 64 символов, просто добавьте md5 из md5, например

$first = md5(uniqid());
$id = $first . md5($first);

Затем, просуммируйте по мере необходимости, если вам нужно меньше, чем несколько кратных 32.

Возможно, вы столкнулись с столкновениями, но это маловероятно. Если вы параноик об этом, просто используйте ту же идею, но chug uniqid() через симметричный шифр, такой как AES, вместо того, чтобы хэшировать его.

Ответ 5

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

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

$randkey = base64_encode(openssl_random_pseudo_bytes(32));

Base64_encode() должен сделать его пригодным для печати. ​​

Причина, по которой другие ответы не рекомендуют openssl_random_pseudo_bytes(), вероятно, что она была введена в PHP 5.3, и этот вопрос составляет почти 6 лет.

Ответ 6

Может ли вас заинтересовать этот вопрос?

Я не уверен, почему uniqid() не работает для вас, и в каком случае вам понадобится уникальный номер за одну миллисекунду, но не обязательно в противном случае; что вы генерируете так быстро, что в той же миллисекунде вы могли столкнуться? Мне интересно, сколько времени занимает uniqid(), чтобы сгенерировать его число. Если вы хотите, используйте префиксный параметр функции uniqid() с помощью нескольких случайных букв, и вы должны быть в безопасности.

Если это для создания файла, вы можете посмотреть tmpfile() или tempname().

В любом случае, в зависимости от того, чего вы пытаетесь достичь, вы можете просто выполнить цикл и проверить, был ли уже выбран уникальный идентификатор (в массиве, с файлами_файлов и т.д.) и просто сгенерировать другой, если это так.


Кроме того, поскольку я не уверен, что я точно понимаю ваш вопрос, я бы указал вам на те другие вопросы, которые звучат довольно похоже, пока я получаю разницу:

Первый будет интересен, если вы хотите сделать уникальный идентификатор, который читается человеком. Второй может быть полезен, если вы хотите играть со случайными числами и md5/sha1. Хотя, опять же, я думаю, uniqid() может быть уже тем, что вы ищете.

Ответ 7

$key = md5 (microtime(). rand());

Microtime сам по себе небезопасен, потому что он оставляет только 1/1000 вероятность угадать.

Rand сам по себе также не очень безопасен, но хеширование их конкатенирования их вместе дает довольно солидную рандомизацию.

Ответ 8

Также вы можете создать случайный ключ и проверить ключ в своей БД, если ключ выйдет, вы можете сгенерировать еще один ключ этим методом.

        function activation($lengt=20){
    $modalpage =new Modal;//you can call your modal page and check the key

    $characters = "1234567890abcdefghijklmnopqrstuvwxyz";
    for($i=0;$i<$lengt;$i++)

    {    

    $key .= $characters{rand(0,35)};
    $check= array(
     ":key" => $key,
    );

     $result = $modalpage->findkey($check);

     if($result==true){ //if the key is exits return the function and generate another key !

        return activation($lengt);   

     }else //if the key is not exits return the key
    return $key;
    }


            } 

$mykey=activation(15);