Току що обявих новия курс Learn Spring , фокусиран върху основите на Spring 5 и Spring Boot 2:
>> ПРЕГЛЕД НА КУРСА1. Общ преглед
В този урок ще обсъдим важността на хеширането на паролата.
Ще разгледаме набързо какво е това, защо е важно и някои сигурни и несигурни начини за това в Java.
2. Какво е хеширане?
Хеширането е процес на генериране на низ или хеш от дадено съобщение с помощта на математическа функция, известна като криптографска хеш функция .
Въпреки че има няколко хеш функции, тези, пригодени за хеширане на пароли, трябва да имат четири основни свойства, за да бъдат сигурни:
- То трябва да бъде детерминирано : едно и също съобщение, обработено от една и съща хеш функция, винаги трябва да генерира един и същ хеш
- Това не е обратимо : непрактично е да се генерира съобщение от неговия хеш
- Той има висока ентропия : малка промяна в съобщението трябва да доведе до значително по-различен хеш
- И се противопоставя на сблъсъци : две различни съобщения не трябва да генерират един и същ хеш
Хеш функция, която има и четирите свойства, е силен кандидат за хеширане на парола, тъй като заедно те значително увеличават трудността при обратното проектиране на паролата от хеша.
Също така, функциите за хеширане на пароли трябва да бъдат бавни . Бързият алгоритъм ще помогне за атаки с груба сила, при които хакер ще се опита да отгатне парола чрез хеширане и сравняване на милиарди (или трилиони) потенциални пароли в секунда.
Някои страхотни хеш функции, които отговарят на всички тези критерии, саPBKDF2, BCrypt и SCrypt. Но първо, нека да разгледаме някои по-стари алгоритми и защо те вече не се препоръчват
3. Не се препоръчва: MD5
Първата ни хеш функция е алгоритъмът за дайджест на съобщенията MD5, разработен още през 1992 година.
MessageDigest на Java улеснява изчисляването и все пак може да бъде полезен при други обстоятелства.
През последните няколко години обаче беше открито , че MD5 проваля четвъртото свойство за хеширане на пароли, тъй като става изчислително лесно за генериране на сблъсъци. На всичкото отгоре MD5 е бърз алгоритъм и следователно безполезен срещу груби атаки.
Поради това MD5 не се препоръчва.
4. Не се препоръчва: SHA-512
След това ще разгледаме SHA-512, която е част от семейството Secure Hash Algorithm, семейство, започнало с SHA-0 през 1993 година.
4.1. Защо SHA-512?
Тъй като компютрите се увеличават и когато откриваме нови уязвимости, изследователите извличат нови версии на SHA. По-новите версии имат постепенно по-голяма дължина или понякога изследователите публикуват нова версия на базовия алгоритъм.
SHA-512 представлява най-дългият ключ в третото поколение на алгоритъма.
Въпреки че сега има по-сигурни версии на SHA , SHA-512 е най-силната, която е внедрена в Java.
4.2. Внедряване в Java
Сега, нека да разгледаме прилагането на алгоритъма за хеширане SHA-512 в Java.
Първо, трябва да разберем понятието сол . Най-просто казано, това е произволна последователност, която се генерира за всеки нов хеш .
Чрез въвеждането на тази случайност увеличаваме ентропията на хеш и защитаваме нашата база данни от предварително съставени списъци с хешове, известни като дъгови таблици .
Тогава нашата нова хеш функция става грубо:
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);
И с добавеното вече можем да използваме метода на дайджест , за да генерираме хешираната си парола:
byte[] hashedPassword = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
4.4. Защо не се препоръчва?
Когато се използва със сол, SHA-512 все още е справедлив вариант, но има по-силни и по-бавни опции .
Също така, останалите опции, които ще покрием, имат важна характеристика: конфигурируема сила.
5. PBKDF2, BCrypt и SCrypt
PBKDF2, BCrypt и SCrypt са три препоръчителни алгоритма.
5.1. Защо се препоръчват тези?
Всеки от тях е бавен и всеки има брилянтната черта да има конфигурируема сила.
This means that as computers increase in strength, we can slow down the algorithm by changing the inputs.
5.2. Implementing PBKDF2 in Java
Now, salts are a fundamental principle of password hashing, and so we need one for PBKDF2, too:
SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt);
Next, we'll create a PBEKeySpec and a SecretKeyFactory which we'll instantiate using the PBKDF2WithHmacSHA1 algorithm:
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
The third parameter (65536) is effectively the strength parameter. It indicates how many iterations that this algorithm run for, increasing the time it takes to produce the hash.
Finally, we can use our SecretKeyFactory to generate the hash:
byte[] hash = factory.generateSecret(spec).getEncoded();
5.3. Implementing BCrypt and SCrypt in Java
So, it turns out that BCrypt and SCrypt support don't yet ship with Java, though some Java libraries support them.
One of those libraries is Spring Security.
6. Password Hashing With Spring Security
Although Java natively supports both the PBKDF2 and SHA hashing algorithms, it doesn't support BCrypt and SCrypt algorithms.
Luckily for us, Spring Security ships with support for all these recommended algorithms via the PasswordEncoder interface:
- MessageDigestPasswordEncoder gives us MD5 and SHA-512
- Pbkdf2PasswordEncoder gives us PBKDF2
- BCryptPasswordEncoder gives us BCrypt, and
- SCryptPasswordEncoder gives us SCrypt
The password encoders for PBKDF2, BCrypt, and SCrypt all come with support for configuring the desired strength of the password hash.
We can use these encoders directly, even without having a Spring Security-based application. Or, if we are protecting our site with Spring Security, then we can configure our desired password encoder through its DSL or via dependency injection.
And, unlike our examples above, these encryption algorithms will generate the salt for us internally. The algorithm stores the salt within the output hash for later use in validating a password.
7. Conclusion
So, we've taken a deep dive into password hashing; exploring the concept and its uses.
And we've taken a look at some historical hash functions as well as some currently implemented ones before coding them in Java.
И накрая, видяхме, че Spring Security се доставя със своите класове за криптиране на пароли, реализирайки масив от различни хеш функции.
Както винаги, кодът е достъпен в GitHub.
Дъно на Java