Стандартный способ создания криптографически безопасного токена с использованием PHP выглядит следующим образом:
$token = bin2hex(openssl_random_pseudo_bytes(16));
Я понимаю, что если вы используете Linux (что я всегда делаю), потому что он использует / dev / urandom — который изменяется в соответствии со всеми многими вещами, происходящими в операционной системе, — это делает почти невозможным прогнозирование.
Моя функция больше похожа на эту, поэтому я могу сделать это по длине символа, а не по длине в битах (хотя я на самом деле никогда не использую это, см. Ниже):
function token($charLength = 32) {
// Each byte produces 2 hexadecimal characters so bit length should be half the char length
$bitLength = $charLength / 2;
// Generate token
$token = bin2hex(openssl_random_pseudo_bytes($bitLength));
return $token;
}
Это непредсказуемость, которая делает его безопасным? Я не могу не думать, что это Меньше безопасный, потому что выходные данные являются шестнадцатеричными и, следовательно, менее трудны для угадывания или грубой силы, чем строка с тем же числом символов, которое содержит остальную часть алфавита, заглавные буквы, другие символы и т. д.
Вот почему, когда люди ссылаются на токены, они ссылаются на длину в битах, а не на длину символа?
Рассмотрим вместо этого:
function randomString($length,
$alpha = true,
$alphau = true,
$numeric = true,
$specialChars = '') {
$string = $specialChars;
if($alpha === true) {
$string .= 'abcdefghijklmnopqrstuvwxyz';
}
if($alphau === true) {
$string .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
}
if($numeric === true) {
$string .= '0123456789';
}
$array = str_split($string);
$string = '';
for($counter = 0; $counter < $length; $counter ++) {
$string .= $array[array_rand($array)];
}
return $string;
}
В контексте веб-разработки, когда бы вы использовали первую функцию над второй для:
Во всех случаях я использовал бы randomString (), а не token (), поэтому, я полагаю, я спрашиваю, не ошибаюсь ли я в чем-либо из вышеперечисленного.
Мое обоснование в отношении вышеуказанных пунктов:
Основной задачей генераторов случайных чисел, как правило, является не созданный вывод, а предсказуемость, в которой генерируются эти данные. Ваш основной вопрос: почему бы не использовать array_rand (который внутренне использует php_rand) поверх openssl_random_pseudo_bytes для криптографических целей. Ответ связан с техникой, которую использует каждая функция, а array_rand — гораздо более предсказуемый (и воспроизводимый) подход. См. Статью Падрайка Брэди «Предсказание случайных чисел в PHP — это проще, чем вы думаете!» для более подробной информации: http://blog.astrumfutura.com/2013/03/predicting-random-numbers-in-php-its-easier-than-you-think/.
Что касается выходных сигналов генераторов случайных чисел, то надежность пароля / ключа в отношении атак методом перебора часто измеряется энтропией. Обычно это указывается в битах, чем больше бит, тем лучше. Страница Википедии о надежности пароля (http://en.wikipedia.org/wiki/Password_strength) имеет несколько великолепных справочных таблиц для определения уровня энтропии паролей различной длины и использования различных комбинаций типов символов. Функция openssl_random_pseudo_bytes () использует все двоичные / шестнадцатеричные значения, что приводит к полному 8 битам энтропии на символ. В лучшем случае ваша функция randomString () будет давать 5,954 бита энтропии на символ.
Использование крипто-сильного случайного числа следует использовать во всех сценариях, связанных с безопасностью, где возможность угадать одно из этих чисел может каким-то образом негативно повлиять на ваш сайт. Единственный элемент в вашем списке из 4, где я вижу, что не требуется крипто-сильное случайное число, это солт-значения для хэшей. Соленость должна быть универсально уникальной. Он, безусловно, может быть получен с помощью криптографического генератора случайных чисел (CRNG), но это не требуется, поскольку полученное значение может быть обнародовано. Увидеть https://security.stackexchange.com/questions/8246/what-is-a-good-enough-salt-for-a-saltedhash
Других решений пока нет …