Hashing di una password in Java

Java Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Panoramica

In questo tutorial, discuteremo l'importanza dell'hashing delle password.

Daremo una rapida occhiata a cos'è, perché è importante e alcuni modi sicuri e insicuri per farlo in Java.

2. Cos'è l'hashing?

L' hash è il processo di generazione di una stringa, o hash , da un determinato messaggio utilizzando una funzione matematica nota come funzione hash crittografica .

Sebbene esistano diverse funzioni hash, quelle personalizzate per l'hashing delle password devono avere quattro proprietà principali per essere sicure:

  1. Dovrebbe essere deterministico : lo stesso messaggio elaborato dalla stessa funzione hash dovrebbe sempre produrre lo stesso hash
  2. Non è reversibile : non è pratico generare un messaggio dal suo hash
  3. Ha un'entropia elevata : una piccola modifica a un messaggio dovrebbe produrre un hash molto diverso
  4. E resiste alle collisioni : due messaggi diversi non dovrebbero produrre lo stesso hash

Una funzione hash che ha tutte e quattro le proprietà è un forte candidato per l'hashing della password poiché insieme aumentano notevolmente la difficoltà di decodificare la password dall'hash.

Inoltre, tuttavia, le funzioni di hashing delle password dovrebbero essere lente . Un algoritmo veloce aiuterebbe gli attacchi di forza bruta in cui un hacker tenterà di indovinare una password eseguendo l'hashing e confrontando miliardi (o trilioni) di potenziali password al secondo.

Alcune ottime funzioni hash che soddisfano tutti questi criteri sonoPBKDF2, BCrypt e SCrypt. Ma prima, diamo un'occhiata ad alcuni algoritmi meno recenti e perché non sono più consigliati

3. Non consigliato: MD5

La nostra prima funzione hash è l'algoritmo di digest di messaggi MD5, sviluppato nel lontano 1992.

MessageDigest di Java lo rende facile da calcolare e può ancora essere utile in altre circostanze.

Tuttavia, negli ultimi anni, è stato scoperto che MD5 non ha superato la quarta proprietà di hashing della password in quanto è diventato computazionalmente facile generare collisioni. Per finire, MD5 è un algoritmo veloce e quindi inutile contro gli attacchi di forza bruta.

Per questo motivo, MD5 non è consigliato.

4. Non consigliato: SHA-512

Successivamente, esamineremo SHA-512, che fa parte della famiglia Secure Hash Algorithm, una famiglia iniziata con SHA-0 nel 1993.

4.1. Perché SHA-512?

Man mano che i computer aumentano di potenza e quando troviamo nuove vulnerabilità, i ricercatori ricavano nuove versioni di SHA. Le versioni più recenti hanno una lunghezza progressivamente maggiore o talvolta i ricercatori pubblicano una nuova versione dell'algoritmo sottostante.

SHA-512 rappresenta la chiave più lunga nella terza generazione dell'algoritmo.

Sebbene ora ci siano versioni più sicure di SHA , SHA-512 è la più potente implementata in Java.

4.2. Implementazione in Java

Ora, diamo un'occhiata all'implementazione dell'algoritmo di hashing SHA-512 in Java.

Innanzitutto, dobbiamo comprendere il concetto di sale . In poche parole, questa è una sequenza casuale generata per ogni nuovo hash .

Introducendo questa casualità, aumentiamo l' entropia dell'hash e proteggiamo il nostro database da elenchi precompilati di hash noti come tabelle arcobaleno .

La nostra nuova funzione hash diventa quindi approssimativamente:

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

4.3. Generare un sale

Per introdurre salt, useremo la classe SecureRandom da java.security :

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

Quindi, useremo la classe MessageDigest per configurare la funzione hash SHA-512 con il nostro salt:

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

E con ciò aggiunto, ora possiamo utilizzare il metodo digest per generare la nostra password con hash:

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

4.4. Perché non è consigliato?

Quando viene utilizzato con il sale, SHA-512 è ancora un'opzione giusta, ma ci sono opzioni più forti e più lente .

Inoltre, le restanti opzioni che tratteremo hanno una caratteristica importante: la forza configurabile.

5. PBKDF2, BCrypt e SCrypt

PBKDF2, BCrypt e SCrypt sono tre algoritmi consigliati.

5.1. Perché sono consigliati?

Ognuno di questi è lento e ognuno ha la brillante caratteristica di avere una forza configurabile.

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.

Infine, abbiamo visto che Spring Security viene fornito con le sue classi di crittografia delle password, implementando una serie di diverse funzioni hash.

Come sempre, il codice è disponibile su GitHub.

Fondo Java

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO