Использование хеш-функции MD5 и пароля при хранении в базе данных

Если у меня есть этот скрипт PHP для системы входа в систему:

$user = $_POST['user_name']; $pass = md5($_POST['user_pass']); require_once("connection_file.php"); $sql = "SELECT * FROM login_table WHERE user_n = :us AND user_p = :password"; $stmt = $conn->prepare($sql); $stmt->bindValue(':us', $user, PDO::PARAM_STR); $stmt->bindValue(':password', $pass, PDO::PARAM_STR); $stmt->execute(); $result = $stmt->fetchAll(); if($result) { //echo $msg = "user exist"; if(session_status() == PHP_SESSION_NONE) { session_start(); foreach($result as $row) { $hash = password_hash($row['user_pass'], PASSWORD_BCRYPT); if(password_verify($row['user_pass'], $hash)) { $_SESSION['userid'] = $row['user_id']; $_SESSION['role'] = $row['user_role']; header("Location: homepage.php"); } } } } else { $msg = "Wrong credentials"; header("Location: login_page.php"); } 

И, как вы видите, я уже сохраняю свой пароль в базе данных как MD5 и я использую $pass = md5($_POST['user_pass']); чтобы проверить, соответствует ли введенный пользователем текст MD5 хэшу.

  1. Теперь мой вопрос: следует ли использовать password_hash и password_verify как я использую в этом скрипте? Или использовать MD5 будет достаточно?

  2. И мой второй вопрос: могу ли я сохранить пароли в базе данных с использованием результата хэш-строки или нормально использовать md5?

Да, вы должны перейти на новый API и никогда не использовать MD5 для этой цели снова, немедленно.


Если вы не используете password_hash() / password_verify() и хотите перенести свой код на более безопасный метод, легко :

  1. Добавьте столбец в таблицу учетных записей пользователей, называемую legacy_password (или эквивалент).
  2. Вычислите хэширование bcrypt существующих хешей MD5 и сохраните их в базе данных (установив legacy_password в TRUE ).
  3. Измените свой код аутентификации для обработки устаревшего флага.

Когда пользователь пытается войти в систему, сначала проверьте, установлен ли флаг legacy_password . Если это так, сначала предоставьте свой пароль с MD5, а затем используйте это предварительное значение вместо своего пароля. Затем пересчитайте хэш-код bcrypt и сохраните новый хеш в базе данных, отключив флаг legacy_password в этом процессе. В PHP 7+ приведен пример:

 /** * This is example code. Please feel free to use it for reference but don't just copy/paste it. * * @param string $username Unsafe user-supplied data: The username * @param string $password Unsafe user-supplied data: The password * @return int The primary key for that user account * @throws InvalidUserCredentialsException */ public function authenticate(string $username, string $password): int { // Database lookup $stmt = $this->db->prepare("SELECT userid, passwordhash, legacy_password FROM user_accounts WHERE username = ?"); $stmt->execute([$username]); $stored = $stmt->fetch(PDO::FETCH_ASSOC); if (!$stored) { // No such user, throw an exception throw new InvalidUserCredentialsException(); } if ($stored['legacy_password']) { // This is the legacy password upgrade code if (password_verify(md5($password), $stored['passwordhash'])) { $newhash = password_hash($password, PASSWORD_DEFAULT); $stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ?, legacy_password = FALSE WHERE userid = ?"); $stmt->execute([$newhash, $stored['userid']]); // Return the user ID (integer) return $stored['userid']; } } elseif (password_verify($password, $stored['passwordhash'])) { // This is the general purpose upgrade code eg if a future version of PHP upgrades to Argon2 if (password_needs_rehash($stored['passwordhash'], PASSWORD_DEFAULT)) { $newhash = password_hash($password, PASSWORD_DEFAULT); $stmt = $this->db->prepare("UPDATE user_accounts SET passwordhash = ? WHERE userid = ?"); $stmt->execute([$newhash, $stored['userid']]); } // Return the user ID (integer) return $stored['userid']; } // When all else fails, throw an exception throw new InvalidUserCredentialsException(); } 

Применение:

 try { $userid = $this->authenticate($username, $password); // Update the session state // Redirect to the post-authentication landing page } catch (InvalidUserCredentialsException $e) { // Log the failure // Redirect to the login form } 

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

Вышеприведенный примерный код также доступен в аромате Bcrypt-SHA-384 .


Кроме того, это не имеет никакого отношения к шифрованию .