Является ли это хорошей функцией пароля хеширования в PHP? Если нет, почему бы и нет?

Мне интересно, действительно ли эта функция (которая частично взята из 2-летней версии phpBB).

Если нет, то почему?
И как бы вы его изменили (сделав переход бесшовным для существующих пользователей)?

Результат hash_pwd () – это то, что будет сохранено в БД.

function hash_pwd($password) { $itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; $random_state = $this->unique_id(); $random = ''; $count = 6; if (($fh = @fopen('/dev/urandom', 'rb'))) { $random = fread($fh, $count); fclose($fh); } if (strlen($random) < $count) { $random = ''; for ($i = 0; $i < $count; $i += 16) { $random_state = md5($this->unique_id() . $random_state); $random .= pack('H*', md5($random_state)); } $random = substr($random, 0, $count); } $hash = $this->_hash_crypt_private($password, $this->_hash_gensalt_private($random, $itoa64), $itoa64); if (strlen($hash) == 34) { return $hash; } return false; } function unique_id() { $val = microtime(); $val = md5($val); return substr($val, 4, 16); } function _hash_crypt_private($password, $setting, &$itoa64) { $output = '*'; // Check for correct hash if (substr($setting, 0, 3) != '$H$') { return $output; } $count_log2 = strpos($itoa64, $setting[3]); if ($count_log2 < 7 || $count_log2 > 30) { return $output; } $count = 1 << $count_log2; $salt = substr($setting, 4, 8); if (strlen($salt) != 8) { return $output; } /** * We're kind of forced to use MD5 here since it's the only * cryptographic primitive available in all versions of PHP * currently in use. To implement our own low-level crypto * in PHP would result in much worse performance and * consequently in lower iteration counts and hashes that are * quicker to crack (by non-PHP code). */ if (PHP_VERSION >= 5) { $hash = md5($salt . $password, true); do { $hash = md5($hash . $password, true); } while (--$count); } else { $hash = pack('H*', md5($salt . $password)); do { $hash = pack('H*', md5($hash . $password)); } while (--$count); } $output = substr($setting, 0, 12); $output .= $this->_hash_encode64($hash, 16, $itoa64); return $output; } function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) { if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) { $iteration_count_log2 = 8; } $output = '$H$'; $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)]; $output .= $this->_hash_encode64($input, 6, $itoa64); return $output; } function _hash_encode64($input, $count, &$itoa64) { $output = ''; $i = 0; do { $value = ord($input[$i++]); $output .= $itoa64[$value & 0x3f]; if ($i < $count) { $value |= ord($input[$i]) << 8; } $output .= $itoa64[($value >> 6) & 0x3f]; if ($i++ >= $count) { break; } if ($i < $count) { $value |= ord($input[$i]) << 16; } $output .= $itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) { break; } $output .= $itoa64[($value >> 18) & 0x3f]; } while ($i < $count); return $output; } 

Код, который вы указали , представляет собой порт PHPASS , в частности «переносимый» алгоритм. Обратите внимание на квалификацию portable . Это применимо только к библиотеке phpass если вы передадите true как второй параметр конструктора. Отсюда в этом ответе, phpass относится ТОЛЬКО к переносимому алгоритму, а не к самой библиотеке. Библиотека будет выполнять bcrypt по умолчанию, если вы явно не укажете portable

Команда PHPBB не развивает себя (очень хорошо), но ее портировали из phpass непосредственно (спорное).

Есть несколько вопросов, которые мы должны задать здесь:

Это плохо?

Короткий ответ – нет, это неплохо. Он предлагает довольно хорошую защиту. Если у вас есть код прямо сейчас, я бы не спешил с ним справиться. Это подходит для большинства обычаев. Но с учетом сказанного, есть намного лучшие альтернативы, если вы начинаете новый проект, который я бы не выбрал.

Какие недостатки?

  • Относительно pbkdf2 : алгоритм phpass использует hash() где pbkdf2() использует hash_hmac() . Теперь HMAC запускает 2 хэша для каждого вызова внутри, но реализация PHP занимает примерно 1,6 раза от выполнения одного вызова hash() (не замечательно?). Таким образом, мы получаем 2 хэша из hash_hmac в 62% случаев, когда hash() выполнил бы 2 хэша.

    Что это значит? Ну, для заданного времени выполнения pbkdf2 будет работать на 37,5% больше хэшей, чем алгоритм phpass . Больше хешей в заданное время == хорошо, потому что это приводит к большему количеству вычислений.

    Таким образом, pbkdf2 примерно на 37.5% сильнее, чем phpass при использовании того же примитива ( md5 в этом случае). Но pbkdf2 также может принимать более примитивные примитивы. Поэтому мы можем использовать pbkdf2 с sha512 чтобы получить очень значительное преимущество над алгоритмом phpass (главным образом потому, что sha512более sha512 алгоритм с большим количеством вычислений, чем md5 ).

    Это означает, что не только pbkdf2 способен генерировать больше вычислений за один и тот же промежуток времени, он способен генерировать более сложные вычисления.

    С учетом сказанного разница не слишком значительна. Это очень измеримо, и pbkdf2 определенно «сильнее», чем phpass .

  • Относительно bcrypt : Это намного сложнее сделать. Но давайте посмотрим на его поверхность. phpass использует md5 и цикл в PHP. pbkdf2 использует любой примитив (в C) и цикл в PHP. bcrypt использует собственный алгоритм в C (это означает, что он отличается от любого доступного хэша). Таким образом, право на летучую мышь, bcrypt имеет значительное преимущество только в том, что алгоритм все в C. Это позволяет больше «вычислений» за единицу времени. Таким образом, это делает более эффективный медленный алгоритм (больше вычислений в данной среде исполнения).

    Но так же важно, как и количество вычислений, которые оно выполняет, – это качество вычислений. Это может быть целый исследовательский документ, но вкратце заключается в том, что вычисления, которые используют bcrypt внутри, намного сложнее, чем обычная хеш-функция.

    Одним из примеров более сильного характера bcrypt является тот факт, что bcrypt использует гораздо большее внутреннее состояние, чем обычная хэш-функция. SHA512 использует 512-битное внутреннее состояние для вычисления против блока 1024 бит. bcrypt использует вместо 32kb внутреннего состояния для вычисления против одного блока из 576 бит. Тот факт, что внутреннее состояние bcrypt намного больше, чем SHA512md5 и phpass ), частично объясняет более сильную природу bcrypt .

Следует ли избегать

Для новых проектов, абсолютно . Дело не в том, что это плохо. Это не так. Это то, что там явно более сильные алгоритмы (на порядок). Так почему бы не использовать их?

Для дальнейшего доказательства того, что bcrypt сильнее, просмотрите слайды из Password13 (PDF), которые запустили кластер 25 GPU для взлома хэшей паролей. Вот соответствующие результаты:

  • md5($password)
    • 180 МЛРД догадок в секунду
    • 9.4 часов – все возможные пароли с 8 символами
  • sha1($password)
    • 61 МЛРД. Догадки в секунду
    • 27 часов – все возможные пароли с 8 символами
  • md5crypt (который очень похож на phpass со стоимостью 10):
    • 77 миллионов догадок в секунду
    • 2.5 года – все возможные пароли с 8 символами
  • bcrypt стоимостью 5
    • 71 Тысяча догадок в секунду
    • 2700 лет – все возможные пароли с 8 символами

Примечание: все возможные 8-символьные пароли используют набор символов 94:

 a-zA-Z0-9~`!@#$%^&*()_+-={}|[]\:";'<>,.?/ 

Нижняя линия

Поэтому, если вы пишете новый код, без сомнений пользуйтесь bcrypt . Если теперь у вас есть phpass или pbkdf2 , вы можете обновить его, но это не четкое сокращение «вы значительно уязвимы».

Быстрый ответ:

Используйте bcrypt (когда он готов) или библиотеку password_compat от ircmaxell – это библиотека bcrypt.

Длительный ответ:

Это слишком сложно и устарело для современных технологий. Md5 следует избегать, и просто соление недостаточно. Используйте bcrypt и сохраняйте головную боль.

Вы можете спросить себя, почему эта конкретная библиотека? Ну, те же функции будут доступны в php 5.5, поэтому вам не придется менять какую-либо кодировку. Желаем удачи и сохраним его просто и эффективно. Также медленный способ хорош для входа в систему и для паролей.

Обновление 1

@ Gumbo -> Нет MD5 не разбит, но основная цель хэшей, таких как MD5, теперь и в прошлом была для проверки файлов (как вы знаете, проверить, можно ли хранить содержимое файла без хранения пароля), поскольку хэши очень быстро расшифровать, так как вы не будете использовать Bcrypt для проверки содержимого файла, так как вы ожидаете 30 – 45 секунд … Таким образом, это означает, что хэш был специально предназначен для быстрого чтения. Даже SHA512 по сравнению с bcrypt все еще уступает полностью. Вот почему необходимо настаивать на сильных алгоритмах пароля, таких как Blowfish / Bcrypt в PHP. Мы, как пользователи и программисты, должны расширить знания о том, что простое хранение паролей или алгоритмы хэширования низкого уровня НЕ являются ответом – и никогда не должны использоваться для такой конфиденциальной информации.

Теперь в OP, чтобы перейти к новой системе, вы должны сначала отправить уведомление всем пользователям, заявив, что «для вашей безопасности система шифрования пароля была обновлена ​​……..», тогда вы спросите их для однократного обновления пароля, как только вы выполните обновление пароля, вы будете использовать функцию password_verify, и если вы хотите иметь максимальный контроль над своим соотношением затрат, вы используете password_needs_rehash, если по какой-то причине вы решите изменить стоимость, связанную с паролями ,

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

Надеюсь, это ответит на большинство вопросов, но, тем не менее, ответ IRCmaxell намного превосходит дальнейшие подробности в отношении различных алгоритмов! Удачи вам, и большое спасибо ircmaxell!

Обновление 2

Кроме того, будет ли пароль, хранящийся таким образом, быть фактически взломанным? как? (Мне сейчас любопытно)

Любая вещь и все сломано, что мой профессор сетевой безопасности говорит мне. Я смеялся над ним. Теперь, когда я вижу вещи в его глазах … ну да … это абсолютно верно!

Bcrypt CURRENTLY – лучший способ хранения паролей! Однако, если вы посмотрите на Scrypt, который кажется перспективным, но не поддерживается PHP. Тем не менее, все, что угодно и все сломано, это просто вопрос времени, пока какой-нибудь «выродка» в подвале не расколот Bcrypt. Но пока мы в безопасности. Так же, как мы в безопасности с IPv4, никогда не заканчивается …. о, подождите? …;)

Надеюсь, это ответит на вашу проблему, которую вы привели сэр. Также для того, чтобы положить его в контекст, моя система стоит 17, и для входа в систему требуется ~ 20 – 30 секунд, но когда я представил систему своему профессору и моим клиентам и почему он должен быть обязательным, они им понравились и были уверены, что они защищены.

Я бы пошел на bcrypt.It хорошо. Помимо включения соли для защиты от атаки с радужным столом, bcrypt – это адаптивная функция: со временем счетчик итераций может быть увеличен, чтобы сделать его медленнее, поэтому он остается стойким к атакам с грубой силой даже с увеличением вычислительной мощности.

Реализация: Как вы используете bcrypt для хеширования паролей в PHP?

(Сначала извините за мой английский)

Существует несколько вопросов, которые все комментаторы должны задать перед ответом:

Где будет использоваться этот код?

Какие данные он будет защищать?

Будет ли он использоваться для системы критического уровня?

Хорошо, у нас есть прецедент. Я использую упрощенный генератор паролей для IS, да, это действительно не «3-я мировая война готова», но вероятность того, что пользователь сообщит кому-то пароль, или он будет просочиться от некоторых вредоносных программ с его компьютера, все еще намного больше.

  • md5 слаб, используйте новейший генератор отпечатков пальцев (sha128, sha256, sha512)
  • используйте соль случайных длин как:

     private function generateSalt() { $salt = ''; $i = rand(20, 40); //min,max length for($length = 0; $length < $i; $length++) { $salt .= chr(rand(33, 126)); } return $salt; } 
  • затем сгенерируйте пароль:

     private function generatePass() { $vocabulary = 'abcdefghijklmnopqrstuvwxyz0123456789'; $password = ''; $i = rand(7,10); for($length = 0; $length < $i; $length++) { $password .= substr($vocabulary,rand(0, 35),1); } return $password.'-'; // avoid copy`n`paste :) } 
  • да пароль должен быть более сильным, но пользователь никогда его не запомнит, он будет сохранен в браузере или где-то написан. Ожидания и безопасность против реальности.

     $newSalt = $this->generateSalt(); $newPass = $this->generatePass(); $newHash = hash('sha512', $newPass.':'.$newSalt); // now store hash and salt into database 
  • Существует новый хеш, но это еще не конец, началась настоящая работа:

    1. Ведение журнала
    2. защита сеанса
    3. пользователь, пользователь + ip, ip temp / perm banning
    4. и т.д

login + logout + re / generate password: 1 или 2 таблицы SQL и несколько килобайт кода

другие вещи о безопасности: много таблиц, на самом деле более нескольких килобайт кода