Генерация соли в PHP
Каков наилучший способ сгенерировать криптографически защищенную 32-байтовую соль в PHP, не зависящую от библиотек, редко включенных в типичные установки PHP?
После некоторого поиска в Google я обнаружил, что mt_rand
считается недостаточно безопасным, но я не нашел предложения по замене. В одной статье предлагалось читать из /dev/random
, но это не только не будет работать в Windows; это также очень медленно.
Я хочу разумного баланса между безопасностью и скоростью (т. Е., для генерации 512 байт не должно потребоваться 20 секунд, как обычно делает /dev/random
)
7 answers
Примечание:
mcrypt
устарел в PHP 7.1. Перейдите к обновленному ответу.
Возможно, вы захотите ознакомиться с документацией (и комментариями) для mcrypt_create_iv()
.
В PHP 7 это проще:
Просто используйте $salt = random_bytes($numberOfDesiredBytes);
для получения соли.
Для чего тебе вообще нужна соль? Если это для паролей, просто используйте password_hash()
и password_verify()
.
Примечание:
mcrypt
устарел в PHP 7.1. Перейдите к обновленному ответу.
Вы можете использовать функцию mycrypt_create_iv()
, поскольку PHP версии 5.3 также использует случайный источник на сервере Windows (не только в Unix). Перед его использованием вы должны проверить, определена ли константа MCRYPT_DEV_URANDOM
.
mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
В отличие от random, urandom не блокирует сервер, если доступной энтропии недостаточно. Поскольку соль пароля должна быть уникальной (не обязательно случайный), urandom кажется мне хорошим выбором.
uniqueid
не очень хорошо подходит для генерации случайной строки, так как она тоже основана на microtime
.
Цикл процессора, как правило, намного короче, чем микротакт, что может привести к возможному постоянству для данной переменной в циклах.
Установка второго параметра "энтропия" в значение true,
uniqid('', true)
Обеспечит повышенную случайность.
Чтобы получить случайную строку, которая хорошо совместима с большинством наборов символов, можно применить кодировку base64 к инициализации mcrypt векторная функция mcrypt_create_iv
:
$length = 16;
base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM))
//> hlZuRJypdHFQPtI2oSFrgA==
strlen(base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM)))
//> 16
Уменьшение алфавита символов до 2^6 бит увеличивает размер, который учитывался выше.
Считывать из /dev/urandom
или использовать openssl_random_pseudo_bytes()
.
Я думаю, что microtime()
достаточно.
Странно, но я все еще получаю отрицательные отзывы за этот ответ.
Хотя единственное объяснение, которое я получаю, заключается в том, что микро-время предсказуемо.
Для меня это звучит странно, так как соль всегда считалась открыто известной - так что предсказывать вообще бесполезно.