Пароль не совпадает после шифрования с использованием функций crypt() и password_hash()

Я изменил свой старый пост. Я попробовал функцию crypt() и теперь пытаюсь работать с password_hash() и password_verify() для проверки зашифрованного пароля, поступающего из базы данных, но при каждом вызове функция password_hash() перенастраивает другую зашифрованную строку и пароль_verify() не может ее сопоставить.

Вот как я это делаю.

 //please ignore the syntax error if any

$data = '11';
$dbpass = password_hash($data, PASSWORD_BCRYPT);
echo $dbpass;  // displays the random strings on each page refresh.

Как только пароль будет сохранен в базе данных, он не получит соответствия во время процесса входа в систему. Ниже приведена моя фактическая функция.

   private function process_data($password){
    $password = __STR.$password.__STR;
    return  password_hash($password, PASSWORD_BCRYPT);

  }
  private function processed($login_password, $dbpassword){
    $login_password = __STR.$login_password.__STR;
    return password_verify($login_password, $dbpassword);
  }

В каждом вызове функции для создания хешированной строки для пароля функция возвращает другую строку в следующий раз.

Ответ 1

Хорошо, пропустите это по одному.

Во-первых, это хеширование, а не шифрование. Шифрование является двусторонним, хеширование - это один из способов. Мы хотим хэш. Мы никогда не хотим шифровать. Да, терминология имеет значение. Используйте правильную терминологию.

Затем каждый вызов password_hash означает предположительно, чтобы вернуть другой хеш. Это потому, что он генерирует сильную случайную соль. Вот как это было разработано и как вы действительно должны его использовать.

Кроме того, НЕ НЕ делать "перец", добавляя __STR до и после пароля. Вы ничего не делаете, но потенциально ослабляете пароль пользователей (что не очень хорошо). Если вам нужна дополнительная информация о том, почему эта плохая идея: Прочитать этот ответ.

Продолжая, я настоятельно рекомендую вам не использовать crypt напрямую. На самом деле удивительно легко завинчивать и генерировать чрезвычайно слабые хеши. Вот почему был разработан дизайн password_* api. crypt - библиотека низкого уровня, вы хотите использовать библиотеку высокого уровня в своем коде. Для получения дополнительной информации о способах испортить bcrypt, просмотрите мой блог: Семь способов накрутить Bcrypt.

API-интерфейс Password был разработан как простой универсальный магазин. Если он не работает для вас, проверьте следующие вещи:

  • Используете ли вы PHP >= 5.5.0? Или вы используете PHP >= 5.3.7 с password_compat?

    • Является ли ваш столбец базы данных достаточно широким?

      Должно быть не менее длиной 60 символов.

    • Проверяете ли вы, что результатом функции является строка, а не bool(false)?

      Если есть внутренняя ошибка, она вернет не строку из password_hash.

    • Вы получаете какие-либо ошибки?

      Вы включили error_reporting в свою максимальную настройку (рекомендую -1 поймать все) и проверили, что код не вызывает ошибок?

    • Вы уверены, что используете его правильно?

      function saveUser($username, $password) {
          $hash = password_hash($password, PASSWORD_BCRYPT);
          // save $username and $hash to db
      }
      function login($username, $password) {
          // fetch $hash from db
          return password_verify($password, $hash);
      }
      

      Обратите внимание, что каждый из них следует вызывать только один раз.

  • Используете ли вы PHP < 5.3.7 с password_compat? Если это так, это ваша проблема. Вы используете библиотеку совместимости на неподдерживаемой версии PHP. Вы можете заставить его работать (некоторые дистрибутивы RedHat предоставили необходимые исправления), но вы используете неподдерживаемую версию. Обновите до разумного выпуска.

Если все остальное не удается, попробуйте запустить этот код и сообщить результат:

$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
$test = crypt("password", $hash);
$pass = $test == $hash;

echo "Test for functionality of compat library: " . ($pass ? "Pass" : "Fail");
echo "\n";

Если это возвращает Fail, вы используете неподдерживаемую версию PHP и должны обновляться. Если он возвращает pass, то ошибка находится где-то в вашей логике (библиотека работает нормально).

Ответ 2

Лучший способ хранения паролей - использовать функцию PHP password_hash(). Он автоматически генерирует криптографически безопасную соль для каждого пароля и включает ее в результирующую 60-значную строку. Вам не придется беспокоиться о соли вообще!

// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
$hashToStoreInDb = password_hash($password, PASSWORD_BCRYPT);

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);

Ваша собственная схема очень слабая, сначала вы используете MD5, который слишком быстро генерирует хэши паролей, тогда вы используете статическую соль, которая побеждает цель соли. Возможно, вы хотите взглянуть на мой учебник о безопасном хранении паролей.

Изменить ответ на обновленный вопрос:

Нет необходимости добавлять __STR к паролю (если вы хотите добавить перец, есть лучшие способы), но ваши функции на самом деле должны работать. Возвращаемое значение password_hash() будет отличаться каждый раз из-за случайной соли. Это правильно, функция password_verify() может извлечь эту соль для проверки. В вашем случае поле базы данных, вероятно, является проблемой. Убедитесь, что он может содержать строку с 60 символами.