Ответ 1
Хорошо, отпустите здесь несколько пунктов
-
То, что у вас есть в
$salt
, не является солью. Он детерминирован (это означает, что в нем нет случайности). Если вы хотите соль, используйтеmcrypt_create_iv($size, MCRYPT_DEV_URANDOM)
или какой-либо другой источник фактической случайной энтропии. Дело в том, что оно должно быть как уникальным, так и случайным. Обратите внимание, что это не должно быть криптографически безопасным случайным... В абсолютном худшем случае я бы сделал что-то вроде этого:function getRandomBytes($length) { $bytes = ''; for ($i = 0; $i < $length; $i++) { $bytes .= chr(mt_rand(0, 255)); } return $bytes; }
-
Как отметил Anony-Mousse, никогда не подает вывод одной хэш-функции в другую без повторного добавления исходных данных к ней. Вместо этого используйте правильный итеративный алгоритм, например PBKDF2, PHPASS или CRYPT_BLOWFISH ($ 2a $).
Мое предложение было бы использовать
crypt
с blowfish, так как это лучшее, что доступно для PHP в это время:function createBlowfishHash($password) { $salt = to64(getRandomBytes(16)); $salt = '$2a$10$' . $salt; $result = crypt($password, $salt); }
И затем проверьте, используя такой метод:
function verifyBlowfishHash($password, $hash) { return $hash == crypt($password, $hash); }
(обратите внимание, что
to64
является хорошим методом, определенным здесь). Вы также можете использоватьstr_replace('+', '.', base64_encode($salt));
...
Я также предлагаю вам прочитать следующие два:
- Фундаментальное различие между хешированием и шифрованием
- Много иетераций хеширования, каждый раз добавляйте соль?
Изменить: ответить на вопрос о миграции
Хорошо, поэтому я понимаю, что мой ответ не касался аспекта миграции исходного вопроса. Итак, вот как я его разрешу.
Сначала создайте временную функцию для создания нового хэша blowfish из исходного хеша md5 со случайной солью и префиксом, чтобы мы могли обнаружить это позже:
function migrateMD5Password($md5Hash) {
$salt = to64(getRandomBytes(16));
$salt = '$2a$10$' . $salt;
$hash = crypt($md5Hash, $salt);
return '$md5' . $hash;
}
Теперь запустите все существующие хеши md5 через эту функцию и сохраните результат в базе данных. Мы помещаем свой собственный префикс, чтобы мы могли обнаружить исходный пароль и добавить дополнительный шаг md5. Итак, теперь мы все мигрировали.
Затем создайте еще одну функцию для проверки паролей и, если необходимо, обновите базу данных новым хешем:
function checkAndMigrateHash($password, $hash) {
if (substr($hash, 0, 4) == '$md5') {
// Migrate!
$hash = substr($hash, 4);
if (!verifyBlowfishHash(md5($password), $hash) {
return false;
}
// valid hash, so let generate a new one
$newHash = createBlowfishHash($password);
saveUpdatedPasswordHash($newHash);
return true;
} else {
return verifyBlowfishHash($password, $hash);
}
}
Вот что я хотел бы предложить по нескольким причинам:
- Он сразу же получает хеширование
md5()
из вашей базы данных. - В конечном итоге (следующий логин для каждого пользователя) обновляет хэш до лучшей альтернативы (тот, который хорошо понимается).
- В коде довольно легко следовать.
Чтобы ответить на комментарии:
-
Соль не обязательно должна быть случайной - я направляю вас на RFC 2898 - Криптография на основе паролей. А именно, раздел 4.1. И я цитирую:
Если нет беспокойства относительно взаимодействия между несколькими видами использования того же ключа (или префикса этого ключа) с паролем, основанные на методах шифрования и аутентификации, поддерживаемые для заданный пароль, то соль может генерироваться произвольно и не нужно проверять конкретный формат стороной получая соль. Он должен быть не менее восьми октетов (64 бит).
Кроме того,
Примечание. Если генератор случайных чисел или псевдослучайный генератор не доступной, детерминированной альтернативой для получения соли (или его случайная часть) заключается в применении вывода на основе пароля функции для пароля и сообщения M, которое должно быть обработано.
Доступен PseudoRandom Generator, так почему бы не использовать его?
-
Является ли ваше решение таким же, как bcrypt? Я не могу найти много документации о том, что такое bcrypt на самом деле?. Я предполагаю, что вы уже прочитали bcrypt Статья в Википедии, и попытайтесь объяснить это лучше.
BCrypt основан на блочном шифре Blowfish. Он использует алгоритм настройки расписания ключей из шифрования и использует это для хеширования паролей. Причина в том, что это хорошо, заключается в том, что алгоритм установки для Blowfish имеет очень высокую стоимость (что является частью того, что делает так сильно похожий на дымку). Основной процесс следующий:
-
18-элементный массив (называемый P-боксами, размером 32 бит) и 4 двумерными массивами (называемые S-блоками, каждый из которых содержит 256 записей по 8 бит каждый) используются для настройки расписания путем инициализации массивов с заданными статическими значениями. Кроме того, 64-разрядное состояние инициализируется для всех 0.
-
Ключ, пройденный, - это XOred со всеми 18 P-боксами (повернуть ключ, если он слишком короткий).
-
Затем поля P используются для шифрования состояния, которое было ранее инициализировано.
-
Зашифрованный текст, созданный на шаге 3, используется для замены P1 и P2 (первые 2 элемента массива P).
-
Шаг 3 повторяется, и результат помещается в P3 и P4. Это продолжается до заполнения P17 и P18.
Это ключевой вывод из Blowfish Cipher. BCrypt модифицирует это:
-
64-разрядное состояние инициализируется зашифрованной версией соли.
-
То же
-
Затем P-поля используются для шифрования (состояния xor-части соли), которая была ранее инициализирована.
-
То же
-
То же
-
Полученная настройка затем используется для шифрования пароля 64 раза. Это то, что было возвращено BCrypt.
Точка проста: это очень дорогостоящий алгоритм, который занимает много процессорного времени. Это настоящая причина, по которой его следует использовать.
-
Я надеюсь, что это прояснит ситуацию.