Хеширование пароля в Java

Хеширование пароля в Java

1. обзор

В этом руководстве мы обсудим важность хеширования паролей.

Мы кратко рассмотрим, что это такое, почему это важно, а также некоторые безопасные и небезопасные способы сделать это на Java.

2. Что за хеширование?

Хеширование - это процесс создания строки илиhash из заданногоmessage с использованием математической функции, известной какcryptographic hash function.

Несмотря на то, что существует несколько хеш-функций, для безопасности паролей должно быть четыре основных свойства:

  1. Это должно бытьdeterministic: одно и то же сообщение, обработанное одной и той же хеш-функцией, должно даватьalways такое жеhash

  2. Это неreversible: непрактично генерироватьmessage из егоhash

  3. У него высокийentropy: небольшое изменениеmessage должно привести к совершенно другомуhash

  4. И он сопротивляетсяcollisions: два разныхmessages не должны давать одинаковыеhash

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

Также, однако,password hashing functions should be slow. Быстрый алгоритм поможетbrute force саттаков, в которых хакер попытается угадать пароль путем хеширования и сравнения миллиардов (or trillions) потенциальных паролей в секунду.

Вот некоторые отличные хэш-функции, которые соответствуют всем этим критериям: PBKDF2, BCrypt, andSCrypt. . Но сначала давайте взглянем на некоторые старые алгоритмы и почему они больше не рекомендуются.

Наша первая хеш-функция - алгоритм дайджеста сообщений MD5, разработанный еще в 1992 году.

MessageDigest в Java упрощает вычисление и может быть полезен в других случаях.

Однако за последние несколько летMD5 was discovered to fail the fourth password hashing property погрешил, что стало вычислительно легко создавать коллизии. В довершение всего, MD5 является быстрым алгоритмом и поэтому бесполезен против атак методом перебора.

По этой причине использование MD5 не рекомендуется.

Затем мы рассмотрим SHA-512, который является частью семейства алгоритмов безопасного хеширования, которое началось с SHA-0 еще в 1993 году.

4.1. Почему именно SHA-512?

По мере увеличения мощности компьютеров и обнаружения новых уязвимостей исследователи получают новые версии SHA. Более новые версии имеют все более длинную длину, или иногда исследователи публикуют новую версию базового алгоритма.

SHA-512 представляет самый длинный ключ в третьем поколении алгоритма.

Покаthere are now more secure versions of SHA,SHA-512 is the strongest that is implemented in Java.

4.2. Реализация на Java

Теперь давайте посмотрим, как реализовать алгоритм хеширования SHA-512 в Java.

Во-первых, мы должны понять концепциюsalt. Проще говоря,this is a random sequence that is generated for each new hash.

Вводя эту случайность, мы увеличиваем хэшentropy и защищаем нашу базу данных от предварительно скомпилированных списков хешей, известных какrainbow tables.

Наша новая хеш-функция становится примерно такой:

salt <- generate-salt;
hash <- salt + ':' + sha512(salt + password)

4.3. Создание соли

Чтобы ввести соль, воспользуемся классомSecureRandom изjava.security:

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

Затем мы воспользуемся классомMessageDigest , чтобы настроить шэш-функциюSHA-512 с нашей солью:

MessageDigest md = MessageDigest.getInstance("SHA-512");
md.update(salt);

И с добавлением этого мы теперь можем использовать методdigest для генерации нашего хешированного пароля:

byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));

При использовании с сольюSHA-512 is still a fair option,but there are stronger and slower options out there.

Кроме того, у остальных параметров, которые мы рассмотрим, есть важная особенность: настраиваемая сила.

5. PBKDF2, BCrypt и SCrypt

PBKDF2, BCrypt и SCrypt - три рекомендуемых алгоритма.

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

Это означает, что по мере увеличения мощности компьютеровwe can slow down the algorithm by changing the inputs.

5.2. Реализация PBKDF2 в Java

Теперьsalts are a fundamental principle of password hashing, значит, нам нужен и для PBKDF2:

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);

Затем мы создадимPBEKeySpec иSecretKeyFactory, которые мы создадим с помощью алгоритмаPBKDF2WithHmacSHA1 :

KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

Третий параметр (65536) фактически является параметром прочности. Он указывает, сколько итераций выполняет этот алгоритм, увеличивая время, необходимое для создания хэша.

Наконец, мы можем использовать нашSecretKeyFactory to для генерации хэша:

byte[] hash = factory.generateSecret(spec).getEncoded();

5.3. Реализация BCrypt и SCrypt в Java

Получается, чтоBCrypt and SCrypt support don’t yet ship with Java, хотя некоторые библиотеки Java поддерживают их.

Одной из таких библиотек является Spring Security.

6. Хеширование паролей с помощью Spring Security

Хотя Java изначально поддерживает алгоритмы хеширования PBKDF2 и SHA, она не поддерживает алгоритмы BCrypt и SCrypt.

К счастью для нас, Spring Security поставляется с поддержкой всех этих рекомендуемых алгоритмов через интерфейсPasswordEncoder:

  • MessageDigestPasswordEncoder  дает нам MD5 и SHA-512

  • Pbkdf2PasswordEncoder дает нам PBKDF2

  • BCryptPasswordEncoder  дает нам BCrypt, а

  • SCryptPasswordEncoder  дает нам SCrypt

Все кодировщики паролей для PBKDF2, BCrypt и SCrypt поддерживают настройку желаемой силы хэша пароля.

Мы можем использовать эти кодировщики напрямую, даже не имея приложения на основе Spring Security. Или, если мы защищаем наш сайт с помощью Spring Security, мы можем настроить желаемый кодировщик паролей через его DSL или черезdependency injection.

И, в отличие от наших примеров выше,these encryption algorithms will generate the salt for us internally. Алгоритм хранит соль в выходном хэше для последующего использования при проверке пароля.

7. Заключение

Итак, мы глубоко погрузились в хеширование паролей; изучение концепции и ее использования.

И мы рассмотрели некоторые исторические хэш-функции, а также некоторые реализованные в настоящее время, прежде чем кодировать их на Java.

Наконец, мы увидели, что Spring Security поставляется со своими классами шифрования паролей, реализуя массив различных хеш-функций.

Как всегда, кодavailable on GitHub.

Related