Hashing eines Passworts in Java

Java Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Übersicht

In diesem Tutorial werden wir die Bedeutung des Passwort-Hashings diskutieren.

Wir werden einen kurzen Blick darauf werfen, was es ist, warum es wichtig ist und einige sichere und unsichere Möglichkeiten, dies in Java zu tun.

2. Was ist Hashing?

Beim Hashing wird aus einer bestimmten Nachricht eine Zeichenfolge oder ein Hash mithilfe einer mathematischen Funktion generiert, die als kryptografische Hash-Funktion bezeichnet wird .

Obwohl es mehrere Hash-Funktionen gibt, müssen diejenigen, die auf Hashing-Passwörter zugeschnitten sind, vier Haupteigenschaften haben, um sicher zu sein:

  1. Es sollte deterministisch sein : Dieselbe Nachricht, die von derselben Hash-Funktion verarbeitet wird, sollte immer denselben Hash erzeugen
  2. Es ist nicht umkehrbar : Es ist unpraktisch, eine Nachricht aus ihrem Hash zu generieren
  3. Es hat eine hohe Entropie : Eine kleine Änderung an einer Nachricht sollte einen völlig anderen Hash erzeugen
  4. Und es widersteht Kollisionen : Zwei verschiedene Nachrichten sollten nicht denselben Hash erzeugen

Eine Hash-Funktion mit allen vier Eigenschaften ist ein starker Kandidat für das Passwort-Hashing, da sie zusammen die Schwierigkeit beim Reverse Engineering des Passworts aus dem Hash dramatisch erhöhen.

Außerdem sollten die Funktionen zum Hashing von Passwörtern langsam sein . Ein schneller Algorithmus würde Brute-Force- Angriffe unterstützen, bei denen ein Hacker versucht, ein Passwort zu erraten, indem er Milliarden (oder Billionen) potenzieller Passwörter pro Sekunde hasht und vergleicht.

Einige großartige Hash-Funktionen, die alle diese Kriterien erfüllen, sindPBKDF2, BCrypt und SCrypt. Aber zuerst werfen wir einen Blick auf einige ältere Algorithmen und warum sie nicht mehr empfohlen werden

3. Nicht empfohlen: MD5

Unsere erste Hash-Funktion ist der MD5-Message-Digest-Algorithmus, der bereits 1992 entwickelt wurde.

Mit MessageDigest von Java ist dies einfach zu berechnen und kann auch unter anderen Umständen nützlich sein.

In den letzten Jahren wurde jedoch festgestellt , dass MD5 die vierte Kennwort-Hashing-Eigenschaft nicht erfüllt , da es rechnerisch einfach wurde, Kollisionen zu generieren. Um das Ganze abzurunden, ist MD5 ein schneller Algorithmus und daher gegen Brute-Force-Angriffe unbrauchbar.

Aus diesem Grund wird MD5 nicht empfohlen.

4. Nicht empfohlen: SHA-512

Als nächstes schauen wir uns SHA-512 an, das Teil der Secure Hash Algorithm-Familie ist, eine Familie, die 1993 mit SHA-0 begann.

4.1. Warum SHA-512?

Wenn die Leistung von Computern zunimmt und wir neue Sicherheitslücken finden, leiten Forscher neue Versionen von SHA ab. Neuere Versionen haben eine zunehmend längere Länge, oder manchmal veröffentlichen Forscher eine neue Version des zugrunde liegenden Algorithmus.

SHA-512 repräsentiert den längsten Schlüssel in der dritten Generation des Algorithmus.

Während es jetzt sicherere Versionen von SHA gibt , ist SHA-512 die stärkste, die in Java implementiert ist.

4.2. Implementierung in Java

Lassen Sie uns nun einen Blick auf die Implementierung des SHA-512-Hashing-Algorithmus in Java werfen.

Zuerst müssen wir das Konzept des Salzes verstehen . Einfach ausgedrückt ist dies eine zufällige Sequenz, die für jeden neuen Hash generiert wird .

Durch die Einführung dieser Zufälligkeit erhöhen wir die Entropie des Hashs und schützen unsere Datenbank vor vorkompilierten Listen von Hashes, die als Regenbogentabellen bezeichnet werden .

Unsere neue Hash-Funktion wird dann ungefähr:

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

4.3. Ein Salz erzeugen

Um Salt einzuführen, verwenden wir die SecureRandom- Klasse von java.security :

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

Dann verwenden wir die MessageDigest- Klasse, um die SHA-512- Hash-Funktion mit unserem Salt zu konfigurieren :

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

Und nachdem dies hinzugefügt wurde, können wir jetzt die Digest- Methode verwenden, um unser Hash-Passwort zu generieren:

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

4.4. Warum wird es nicht empfohlen?

Wenn SHA-512 mit Salz verwendet wird, ist es immer noch eine faire Option, aber es gibt stärkere und langsamere Optionen .

Die verbleibenden Optionen, die wir behandeln, haben ein wichtiges Merkmal: konfigurierbare Stärke.

5. PBKDF2, BCrypt und SCrypt

PBKDF2, BCrypt und SCrypt sind drei empfohlene Algorithmen.

5.1. Warum werden diese empfohlen?

Jedes von diesen ist langsam und jedes hat das brillante Merkmal, eine konfigurierbare Stärke zu haben.

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.

Schließlich haben wir gesehen, dass Spring Security mit seinen Kennwortverschlüsselungsklassen ausgeliefert wird, die eine Reihe verschiedener Hash-Funktionen implementieren.

Wie immer ist der Code auf GitHub verfügbar.

Java unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs