Генерация уникальных ключей - PullRequest
12 голосов
/ 11 сентября 2008

Я искал способ, особенно в PHP, чтобы я всегда гарантированно получал уникальный ключ.

Я сделал следующее:

strtolower(substr(crypt(time()), 0, 7));

Но я обнаружил, что время от времени я получаю дубликат ключа (редко, но достаточно часто).

Я тоже думал о том, чтобы сделать:

strtolower(substr(crypt(uniqid(rand(), true)), 0, 7));

Но, согласно веб-сайту PHP, uniqid () может, если uniqid () вызывается дважды в течение одной микросекунды, он может генерировать один и тот же ключ. Я думаю, что добавление rand (), что это было бы редко, но все же возможно.

После строк, упомянутых выше, я также удаляю такие символы, как L и O, так что это менее запутанно для пользователя. Это может быть частью причины для дубликатов, но все же необходимо.

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

Есть еще мысли? Существуют ли какие-либо сайты, которые уже делают это, имеют какой-то API или просто возвращают ключ. Я нашел http://userident.com, но я не уверен, будут ли ключи полностью уникальными.

Это должно выполняться в фоновом режиме без какого-либо ввода пользователя.

Ответы [ 13 ]

19 голосов
/ 11 сентября 2008

Существует только 3 способа генерирования уникальных значений, это могут быть пароли, идентификаторы пользователей и т. Д.:

  1. Используйте эффективный генератор GUID - они длинные и не могут быть сокращены. Если вы используете только часть , вы FAIL .
  2. По крайней мере, часть номера последовательно генерируется из одной последовательности. Вы можете добавить пух или кодировку, чтобы она выглядела менее последовательной. Преимущество в том, что они начинаются с короткого, а недостаток в том, что они требуют одного источника Обходной путь для ограничения одного источника состоит в том, чтобы иметь нумерованные источники, поэтому вы включаете [source #] + [seq #], и тогда каждый источник может генерировать свою собственную последовательность.
  3. Генерируйте их с помощью других средств, а затем сверяйте их с единой историей ранее сгенерированных значений.

Любой другой метод не гарантируется. Имейте в виду, что в основном вы генерируете двоичное число (это компьютер), но затем вы можете закодировать его в шестнадцатеричном, десятичном, Base64 или списке слов. Выберите кодировку, которая подходит для вашего использования. Обычно для данных, вводимых пользователем, вам нужен вариант Base32 (на который вы намекали).

Примечание о GUIDS : Они получают силу уникальности от своей длины и метода, используемого для их создания. Все, что меньше 128 бит, небезопасно. Помимо генерации случайных чисел существуют характеристики, которые входят в GUID, чтобы сделать его более уникальным. Имейте в виду, что они только практически уникальны, но не полностью уникальны. Возможно, хотя практически невозможно иметь дубликат.

Обновленное примечание о GUIDS : С момента написания этого я узнал, что многие генераторы GUID используют криптографически безопасный генератор случайных чисел (сложно или невозможно предсказать следующее сгенерированное число, и вряд ли будет повторяться). На самом деле существует 5 различных UUID алгоритмов . Алгоритм 4 - это то, что Microsoft в настоящее время использует для API генерации GUID Windows. GUID - это реализация Microsoft стандарта UUID.

Обновление : если вы хотите от 7 до 16 символов, вам нужно использовать либо метод 2, либо 3.

Итог : Честно говоря, не существует такой вещи, как полностью уникальная. Даже если бы вы использовали последовательный генератор, вы в конечном итоге исчерпали бы хранилище, используя все атомы во вселенной, таким образом возвращаясь к себе и повторяя. Ваша единственная надежда будет тепловой смерть вселенной до достижения этой точки.

Даже лучший генератор случайных чисел имеет возможность повторения, равную общему размеру генерируемого вами случайного числа. Взять хотя бы четверть. Это совершенно случайный битовый генератор, и его шансы на повторение равны 1 к 2.

Так что все сводится к вашему порогу уникальности. Вы можете иметь 100% уникальность в 8 цифр для 1 099 511 627 776 номеров, используя последовательность, а затем кодируя ее base32. Любой другой метод, который не включает проверку по списку прошлых чисел, имеет шансы, равные n / 1 099 511 627 776 (где n = число сгенерированных предыдущих чисел), не быть уникальными.

1 голос
/ 11 сентября 2008

Любой алгоритм приведет к дублированию .

Поэтому, могу ли я предложить вам использовать существующий алгоритм * и просто проверить наличие дубликатов?

* Незначительное добавление: если uniqid() может быть неуникальным в зависимости от времени, также включите глобальный счетчик, который вы увеличиваете после каждого вызова. Таким образом, что-то другое даже в одну микросекунду.

0 голосов
/ 18 марта 2010

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

function GetUniqueValue()
{
   static $counter = 0; //initalized only 1st time function is called
   return strtr(microtime(), array('.' => '', ' ' => '')) . $counter++;
}

При вызове в одном и том же процессе $ counter увеличивается, поэтому значение всегда уникально в одном и том же процессе.

При вызове в разных процессах вам должно быть не повезло получить 2 вызова microtime () с одинаковыми значениями, подумайте, что вызовы microtime () обычно имеют разные значения также при вызове в одном и том же скрипте.

0 голосов
/ 15 сентября 2009

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

$ukey = dechex(time()) . crypt( time() . md5(microtime() + mt_rand(0, 100000)) ); 

Итак, в основном я получаю Unix-время в секундах и добавляю случайную строку md5, сгенерированную из времени + случайного числа. Это не самое лучшее, но для низкочастотных запросов это довольно хорошо. Это быстро и работает.

Я провел тест, в котором я генерировал тысячи ключей, а затем искал повторы, и, имея около 800 ключей в секунду, повторений не было, так что неплохо. Я думаю, это полностью зависит от mt_rand ()

Я использую его для трекера опросов, где мы получаем скорость отправки около 1000 опросов в минуту ... так что на данный момент (пересекает пальцы) дубликатов нет. Конечно, скорость не постоянна (мы получаем данные в определенное время дня), так что это не является ни доказательством отказа, ни лучшим решением ... совет использует инкрементное значение как часть ключа (в моем случае, Я использовал time (), но мог бы быть лучше).

0 голосов
/ 12 сентября 2008

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

это действительно две разные проблемные области, и на самом деле не стоит пытаться решать их вместе.

0 голосов
/ 11 сентября 2008

Я до сих пор не понимаю, почему пароли должны быть уникальными? В чем недостаток, если 2 ваших пользователя имеют одинаковый пароль?

Это предполагает, что мы говорим о паролях, привязанных к идентификаторам пользователей, а не только об уникальных идентификаторах. Если это , что вы ищете, почему бы не использовать GUID?

0 голосов
/ 11 сентября 2008

Как прокомментировал Фрэнк Кройгер, используйте генератор GUID.

Как этот

0 голосов
/ 11 сентября 2008

Возможно, вас заинтересует сверх-защищенная реализация Стивом Гибсоном генератора паролей (без источника, но у него есть подробное описание его работы) на https://www.grc.com/passwords.htm.

Сайт создает огромные 64-символьные пароли, но, поскольку они абсолютно случайные, вы можете легко взять первые 8 (или сколько угодно) символов для менее безопасного, но "как можно более случайного" пароля.

РЕДАКТИРОВАТЬ: из ваших более поздних ответов я вижу, что вам нужно нечто большее, чем GUID, чем пароль, так что это, вероятно, не то, что вы хотите ...

0 голосов
/ 11 сентября 2008

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

0 голосов
/ 11 сентября 2008

Я обычно делаю это так:

$this->password = '';

for($i=0; $i<10; $i++)
{
    if($i%2 == 0)
        $this->password .= chr(rand(65,90));
    if($i%3 == 0)
        $this->password .= chr(rand(97,122));
    if($i%4 == 0)
        $this->password .= chr(rand(48,57));
}

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

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