Рубрики
Без рубрики

Как правильно хранить пароль в базе данных

Статья, первоначально опубликованная на моем сайте, о том, как безопасно хранить пароль в базе данных (https://petrepopescu.tech/2021/01/how-to-properly-store-a-password-in-the-database/) Когда я начал…

Автор оригинала: Petre Popescu.

Статья, первоначально размещенная на моем сайте в разделе Как безопасно сохранить пароль в базе данных

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

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

Итак, прежде чем я покажу вам, как правильно хранить пароль (и какой механизм я использовал для логарифмирования), позвольте мне сразу сказать вам, как ЭТОГО НЕ делать:

  • Открытый текст – НИКОГДА НЕ ХРАНИТЕ ПАРОЛИ В ОТКРЫТОМ ВИДЕ – я не могу поверить, что должен это сказать. Пароли не должны храниться в открытом тексте, потому что любой дамп базы данных может легко извлечь комбинацию электронной почты и пароля и опробовать ее на других веб-сайтах.
  • Используйте свой собственный алгоритм – Если вы не гений в математике и шифровании, не пишите свои собственные алгоритмы для шифрования или хэширования пароля. Это может быть не так безопасно, как вы думаете.
  • Простой хэш – Хотя и не такой плохой, как первые два, он не очень далеко. Существуют атаки с использованием радужных таблиц, которые можно выполнить на дампе базы данных, и большинство паролей можно легко восстановить. Радужная таблица-это предварительно вычисленный файл, содержащий известный хэш для многих паролей. Файл может хранить сотни тысяч паролей и их хэш с различными алгоритмами. Далее, это просто вопрос сопоставления хэшей базы данных с предварительно рассчитанным файлом. Не все пароли будут восстановлены, но большинство из них будут восстановлены.

Как безопасно сохранить пароль в базе данных

Лучший способ сохранить пароль в базе данных-это использовать алгоритм хэширования с солью. Таким образом, даже в случае утечки дампа БД восстановить пароли будет практически невозможно. Как помогает добавление соли? Во-первых, давайте объясним, в чем соль. Соль хэша-это случайно выбранная строка (или байты), которая добавляется к паролю перед его хэшированием. На самом деле не имеет значения, добавляете вы его или добавляете, если вы последовательны и соль достаточно сильна.

В базе данных вы храните соль для каждого пользователя и полученный хэш для соли+пароль. Имейте в виду (и это очень важно), что у каждого пользователя должна быть своя соль, и ее необходимо менять всякий раз, когда меняется пароль. Кроме того, чтобы быть уверенным, что соль достаточно сильна, рекомендуется иметь длину не менее 64 байт.

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

Алгоритмы хэширования обычно имеют несколько итераций. Здесь мы должны быть последовательными, так как это повлияет на вывод, даже если соль и пароли совпадают. Однако имейте в виду, что чем больше число итераций, тем больше времени потребуется для вычисления хэша. Это здорово, так как сводит к минимуму вероятность того, что кто-то совершит атаку грубой силы в случае утечки дампа БД. Проведите некоторое тестирование, чтобы увидеть, какое количество итераций подходит для вашей системы, без какой-либо серьезной нагрузки на нее.

Как проверить правильность введенного пароля?

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

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

Как я хранил пароли в логарифмическом

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

  • Длина соли – 521 байт
  • Размер хеш – байта-256
  • Итерация – 1000
  • Алгоритм – PBKDF2WithHmacSHA512
  • Всегда использовал SecureRandom

Ниже приведена часть служебного класса (в том виде, в каком он в настоящее время находится в проекте). Для получения полной и обновленной версии не стесняйтесь просматривать код в логарифмическом репо.

/**
 * Generates a cryptographically secure 512 bytes string that can be used as a password salt
 */
public static String generateSalt() {
    byte[] bytes = new byte[512];
    secureRandom.nextBytes(bytes);
    return Base64.getEncoder().encodeToString(bytes);
}

/**
 * Generate a hash for a password
 */
public static String generateHashForPassword(String password, String salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
    byte[] hash = secretKeyFactory.generateSecret(spec).getEncoded();
    return Base64.getEncoder().encodeToString(hash);
}

Оригинал: “https://www.codementor.io/@petrepopescu/how-to-properly-store-a-password-in-the-database-1k0qcoog92”