Hachage d'un mot de passe en Java

Haut Java

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS

1. Vue d'ensemble

Dans ce didacticiel, nous discuterons de l'importance du hachage des mots de passe.

Nous allons jeter un rapide coup d'œil à ce que c'est, pourquoi c'est important et quelques moyens sécurisés et non sécurisés de le faire en Java.

2. Qu'est-ce que le hachage?

Le hachage est le processus de génération d'une chaîne, ou hachage , à partir d'un message donné à l' aide d'une fonction mathématique connue sous le nom de fonction de hachage cryptographique .

Bien qu'il existe plusieurs fonctions de hachage, celles adaptées aux mots de passe de hachage doivent avoir quatre propriétés principales pour être sécurisées:

  1. Il doit être déterministe : le même message traité par la même fonction de hachage doit toujours produire le même hachage
  2. Ce n'est pas réversible : il est impossible de générer un message à partir de son hachage
  3. Il a une entropie élevée : un petit changement dans un message devrait produire un hachage très différent
  4. Et il résiste aux collisions : deux messages différents ne doivent pas produire le même hachage

Une fonction de hachage qui possède les quatre propriétés est un bon candidat pour le hachage de mot de passe car, ensemble, elles augmentent considérablement la difficulté de rétro-ingénierie du mot de passe à partir du hachage.

De plus, les fonctions de hachage de mot de passe devraient être lentes . Un algorithme rapide faciliterait les attaques par force brute dans lesquelles un pirate tentera de deviner un mot de passe en hachant et en comparant des milliards (ou des billions) de mots de passe potentiels par seconde.

Certaines fonctions de hachage qui répondent à tous ces critères sontPBKDF2, BCrypt et SCrypt. Mais d'abord, examinons certains algorithmes plus anciens et pourquoi ils ne sont plus recommandés

3. Non recommandé: MD5

Notre première fonction de hachage est l'algorithme de résumé de message MD5, développé en 1992.

MessageDigest de Java facilite le calcul et peut toujours être utile dans d'autres circonstances.

Cependant, au cours des dernières années, il a été découvert que MD5 échouait à la quatrième propriété de hachage de mot de passe en ce sens qu'il devenait facile par calcul de générer des collisions. Pour couronner le tout, MD5 est un algorithme rapide et donc inutile contre les attaques par force brute.

Pour cette raison, MD5 n'est pas recommandé.

4. Non recommandé: SHA-512

Ensuite, nous examinerons SHA-512, qui fait partie de la famille Secure Hash Algorithm, une famille qui a commencé avec SHA-0 en 1993.

4.1. Pourquoi SHA-512?

À mesure que la puissance des ordinateurs augmente et que nous découvrons de nouvelles vulnérabilités, les chercheurs dérivent de nouvelles versions de SHA. Les versions plus récentes ont une longueur progressivement plus longue, ou parfois les chercheurs publient une nouvelle version de l'algorithme sous-jacent.

SHA-512 représente la clé la plus longue de la troisième génération de l'algorithme.

Bien qu'il existe maintenant des versions plus sécurisées de SHA , SHA-512 est la plus puissante implémentée en Java.

4.2. Implémentation en Java

Voyons maintenant l'implémentation de l'algorithme de hachage SHA-512 en Java.

Premièrement, nous devons comprendre le concept de sel . En termes simples, il s'agit d'une séquence aléatoire générée pour chaque nouveau hachage .

En introduisant ce caractère aléatoire, nous augmentons l' entropie du hachage et nous protégeons notre base de données contre les listes pré-compilées de hachages connues sous le nom de tables arc- en- ciel .

Notre nouvelle fonction de hachage devient alors à peu près:

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

4.3. Générer un sel

Pour introduire le sel, nous allons utiliser la SecureRandom classe de java.security :

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

Then, we'll use the MessageDigest class to configure the SHA-512 hash function with our salt:

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

And with that added, we can now use the digest method to generate our hashed password:

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

4.4. Why Is It Not Recommended?

When employed with salt, SHA-512 is still a fair option, but there are stronger and slower options out there.

Also, the remaining options we'll cover have an important feature: configurable strength.

5. PBKDF2, BCrypt, and SCrypt

PBKDF2, BCrypt, and SCrypt are three recommended algorithms.

5.1. Why Are Those Recommended?

Each of these is slow, and each has the brilliant feature of having a configurable strength.

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.

Enfin, nous avons vu que Spring Security est livré avec ses classes de cryptage de mot de passe, implémentant un tableau de différentes fonctions de hachage.

Comme toujours, le code est disponible sur GitHub.

Fond Java

Je viens d'annoncer le nouveau cours Learn Spring , axé sur les principes de base de Spring 5 et Spring Boot 2:

>> VOIR LE COURS