Каков наилучший способ генерировать случайный ключ в PHP? - PullRequest
38 голосов
/ 12 марта 2009

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

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

Ответы [ 8 ]

56 голосов
/ 12 марта 2009

Обновление (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 (который я не тестировал ... пока)

28 голосов
/ 11 мая 2011

Ни один из ответов здесь не является достаточным, если вы хотите получить случайную криптографическую силу (неужели решительный злоумышленник пытается угадать, какие у вас случайные ключи?). Хэширование времени небезопасно, злоумышленник может значительно ускорить свой поиск, приблизительно угадав время, когда, по его мнению, ваш сервер сгенерировал ключ, и поиск по всем миллисекундам в конкретном году выполняется легко, даже на обычном ноутбуке (это 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.

8 голосов
/ 12 марта 2009

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

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

$id = md5(uniqid());

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

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

Затем, если нужно, умножьте, если вам нужно кратное 32.

Возможно, вы можете столкнуться со столкновениями, но это маловероятно. Если вы параноики по этому поводу, просто используйте ту же идею, но вместо хеширования

используйте uniqid() через симметричный шифр, такой как AES.
3 голосов
/ 02 декабря 2013

Почему бы не использовать openssl_random_pseudo_bytes http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php

1 голос
/ 04 марта 2015

В моем предыдущем ответе использовался хеш uniqid () в сочетании с солью, полученной из системных переменных, но он не генерирует ключ random , только тот, который с большой вероятностью будет уникальным. Аналогично, выходные данные из 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 лет.

0 голосов
/ 20 апреля 2015

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

        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);
0 голосов
/ 10 апреля 2014

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

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

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

0 голосов
/ 12 марта 2009

интересует ли вас *1001* этот вопрос?

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

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

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


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

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

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