md5 (uniqid) имеет смысл для случайных уникальных токенов? - PullRequest
33 голосов
/ 07 апреля 2010

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

Я часто вижу этот код; имеет ли смысл?

md5(uniqid(rand(), true));

Согласно комментарию uniqid($prefix, $moreEntopy = true) доходность

первые 8 шестнадцатеричных символов = время Unix, последние 5 шестнадцатеричных символов = микросекунды.

Я не знаю, как обрабатывается $prefix -параметр ..

Так что, если вы не установите флаг $ moreEntopy в true, это даст предсказуемый результат.


ВОПРОС: Но если мы используем uniqid с $moreEntopy, что хешинг с md5 покупает нас? Это лучше чем:

md5(mt_rand())

edit1: Я буду хранить этот токен в столбце базы данных с уникальным индексом, поэтому буду обнаруживать столбцы. Может представлять интерес /

Ответы [ 8 ]

43 голосов
/ 07 апреля 2010

rand () представляет собой угрозу безопасности и никогда не должна использоваться для создания токена безопасности: rand () vs mt_rand () (посмотрите на «статические» подобные изображения). Но ни один из этих методов генерации случайных чисел не является криптографически безопасным. Для создания защищенных секций необходимо, чтобы приложение получило доступ к CSPRNG , предоставляемому платформой, операционной системой или аппаратным модулем.

В веб-приложении хорошим источником безопасных секретов является неблокирующий доступ к пулу энтропии, например /dev/urandom. Начиная с PHP 5.3 приложения PHP могут использовать openssl_random_pseudo_bytes(), а библиотека Openssl будет выбирать лучший источник энтропии на основе вашей операционной системы, в Linux это означает, что приложение будет использовать /dev/urandom. Этот фрагмент кода от Скотта довольно хорош :

function crypto_rand_secure($min, $max) {
        $range = $max - $min;
        if ($range < 0) return $min; // not so random...
        $log = log($range, 2);
        $bytes = (int) ($log / 8) + 1; // length in bytes
        $bits = (int) $log + 1; // length in bits
        $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
            $rnd = $rnd & $filter; // discard irrelevant bits
        } while ($rnd >= $range);
        return $min + $rnd;
}

function getToken($length=32){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    for($i=0;$i<$length;$i++){
        $token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
    }
    return $token;
}
21 голосов
/ 06 декабря 2012

Это копия другого вопроса, который я нашел, который был задан за несколько месяцев до этого. Вот ссылка на вопрос и мой ответ: https://stackoverflow.com/a/13733588/1698153.

Я не согласен с принятым ответом. По данным собственного сайта PHPs "[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."

Я не думаю, что ответ может быть яснее, чем это, uniqid небезопасно.

5 голосов
/ 17 ноября 2016

Я знаю, что вопрос старый, но он появляется в Google, так что ...

Как уже говорили другие, rand(), mt_rand() или uniqid() не гарантируют вашу уникальность ... даже openssl_random_pseudo_bytes() не следует использовать, поскольку он использует устаревшие функции OpenSSL .

То, что вы должны использовать для генерации случайного хэша (аналогично md5), это random_bytes () (введено в PHP7). Чтобы сгенерировать хеш такой же длины, как MD5:

bin2hex(random_bytes(16));

Если вы используете PHP 5.x, вы можете получить эту функцию, включив random_compat library .

1 голос
/ 18 мая 2011

Я столкнулся с интересной идеей пару лет назад.
Сохранение двух значений хеша в базе данных, одно сгенерированное с помощью md5 ($ a), а другое с помощью sha ($ a). Затем проверьте, если оба значения являются основными. Дело в том, что если атакующий сломал ваш md5 (), он не сможет сломать ваш md5 AND sha в ближайшем будущем.
Проблема заключается в следующем: как можно использовать эту концепцию при создании токена, необходимого для вашей проблемы?

1 голос
/ 07 апреля 2010

Чтобы ответить на ваш вопрос, проблема в том, что вы не можете иметь генератор, который гарантированно является случайным и уникальным как случайный сам по себе, то есть md5(mt_rand()) может привести к дублированию.То, что вы хотите, это «случайное появление» уникальных значений.uniqid дает уникальный идентификатор, rand () добавляет случайное число, что делает его еще сложнее угадать, md5 маскирует результат, чтобы сделать его еще сложнее угадать.Ничего не угадывается.Нам просто нужно сделать так, чтобы они даже не захотели попробовать.

1 голос
/ 07 апреля 2010

Определить «уникальный». Если вы имеете в виду, что два токена не могут иметь одно и то же значение, то хэширования недостаточно - это должно быть подтверждено тестом уникальности. Тот факт, что вы предоставляете алгоритму хеширования уникальные входные данные, не гарантирует уникальные выходные данные.

0 голосов
/ 18 апреля 2018

Во-первых, целью этой процедуры является создание ключа / хеша / кода, который будет уникальным для одной данной базы данных.Невозможно создать что-то уникальное для всего мира в данный момент.Тем не менее, вы должны создать простую, видимую строку, используя собственный алфавит, и проверить созданный код в вашей базе данных (таблица).Если эта строка уникальна, тогда вы применяете md5() к ней, и никто не может угадать ее или любой скрипт.Я знаю, что если вы углубитесь в теорию генерации криптографии, вы сможете найти много объяснений такого рода генерации кода, но когда вы используете его на практике, это действительно не так сложно.

Вот кодЯ использую для генерации простого 10-значного уникального кода.

$alphabet = "aA1!bB2@cC3#dD5%eE6^fF7&gG8*hH9(iI0)jJ4-kK=+lL[mM]nN{oO}pP\qQ/rR,sS.tT?uUvV>xX~yY|zZ`wW$";
$code = '';
$alplhaLenght = strlen($alphabet )-1;
for ($i = 1; $i <= 10; $i++) {
    $n = rand(1, $alplhaLenght );
    $code .= $alphabet [$n];
}

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

SpQ0T0tyO%
Uwn[MU] [.
D | [ROt + Cd @
O6I | w38TRe

Конечно, может быть много «улучшений», которые можно применить к нему, чтобы сделать его более «сложным»msgstr ", но если вы примените md5() к этому, он станет, скажем," неузнаваемым ".:)

0 голосов
/ 07 апреля 2010

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

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

Но для более сильного распределения ключей я бы лично использовал SHA1 или SHAx и т. д. '... но у вас все равно будет проблемапохожие данные приводят к аналогичным ключам.

...