Hashing eines Passworts in Java

Hashing eines Passworts in Java

1. Überblick

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?

Hashing ist der Prozess des Erzeugens eines Strings oderhash aus einem gegebenenmessage unter Verwendung einer mathematischen Funktion, die alscryptographic hash function bekannt ist.

Obwohl es mehrere Hash-Funktionen gibt, müssen die auf Hashing-Passwörter zugeschnittenen über vier Haupteigenschaften verfügen, um sicher zu sein:

  1. Es solltedeterministic sein: Dieselbe Nachricht, die von derselben Hash-Funktion verarbeitet wird, solltealways dieselbehash erzeugen

  2. Es ist nichtreversible: Es ist unpraktisch, aushash einmessage zu generieren

  3. Es hat hoheentropy: Eine kleine Änderung von amessage sollte zu sehr unterschiedlichenhash führen

  4. Und es widerstehtcollisions: Zwei verschiedenemessages sollten nicht die gleichenhash erzeugen

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

Aber auchpassword hashing functions should be slow. Ein schneller Algorithmus würdebrute force attacks unterstützen, bei denen ein Hacker versucht, ein Passwort zu erraten, indem er Milliarden (or trillions) potenzieller Passwörter pro Sekunde hasht und vergleicht.

Einige großartige Hash-Funktionen, die alle diese Kriterien erfüllen, sind PBKDF2, BCrypt, andSCrypt. . Schauen wir uns zunächst einige ältere Algorithmen an und erklären, warum sie nicht mehr empfohlen werden

Unsere erste Hash-Funktion ist der bereits 1992 entwickelte MD5-Message-Digest-Algorithmus.

JavaMessageDigest macht dies einfach zu berechnen und kann unter anderen Umständen immer noch nützlich sein.

In den letzten Jahren hatMD5 was discovered to fail the fourth password hashing property jedoch festgestellt, dass es rechnerisch einfach wurde, Kollisionen zu erzeugen. Um das Ganze abzurunden, MD5 ist ein schneller Algorithmus und daher gegen Brute-Force-Angriffe nutzlos.

Aus diesem Grund wird MD5 nicht empfohlen.

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 neue Sicherheitslücken gefunden werden, leiten die Forscher neue Versionen von SHA ab. Neuere Versionen werden immer länger, 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ährendthere are now more secure versions of SHA,SHA-512 is the strongest that is implemented in Java.

4.2. Implementierung in Java

Schauen wir uns nun die Implementierung des SHA-512-Hashing-Algorithmus in Java an.

Zunächst müssen wir das Konzept vonsalt verstehen. Einfach ausgedrückt,this is a random sequence that is generated for each new hash.

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

Unsere neue Hash-Funktion wird dann ungefähr:

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

4.3. Ein Salz erzeugen

Um Salz einzuführen, verwenden wir dieSecureRandom -Schale vonjava.security:

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

Dann verwenden wir dieMessageDigest -Schlasse, um dieSHA-512 -Shash-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 diedigest-Methode verwenden, um unser Hash-Passwort zu generieren:

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

Bei Verwendung mit SalzSHA-512 is still a fair option,but there are stronger and slower options out there.

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.

Jedes davon ist langsam und hat die brillante Eigenschaft, eine konfigurierbare Stärke zu haben.

Dies bedeutet, dass mit zunehmender Stärke des Computerswe can slow down the algorithm by changing the inputs.

5.2. Implementierung von PBKDF2 in Java

Nun,salts are a fundamental principle of password hashing, und so brauchen wir auch eine für PBKDF2:

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

Als Nächstes erstellen wir einPBEKeySpec und einSecretKeyFactory, die wir mithilfe desPBKDF2WithHmacSHA1 -Salgorithmus instanziieren:

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

Der dritte Parameter (65536) ist effektiv der Festigkeitsparameter. Es gibt an, wie viele Iterationen dieser Algorithmus ausführt, wodurch die Zeit für die Erstellung des Hashs verlängert wird.

Schließlich können wir unserSecretKeyFactory verwenden, um den Hash zu generieren:

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

5.3. Implementierung von BCrypt und SCrypt in Java

Es stellt sich also heraus, dassBCrypt and SCrypt support don’t yet ship with Java, obwohl einige Java-Bibliotheken sie unterstützen.

Eine dieser Bibliotheken ist Spring Security.

6. Passwort-Hashing mit Spring Security

Obwohl Java nativ sowohl den PBKDF2- als auch den SHA-Hashing-Algorithmus unterstützt, werden BCrypt- und SCrypt-Algorithmen nicht unterstützt.

Zum Glück bietet Spring Security Unterstützung für all diese empfohlenen Algorithmen über diePasswordEncoder-Schnittstelle:

  • MessageDigestPasswordEncoder gibt uns MD5 und SHA-512

  • Pbkdf2PasswordEncoder gibt uns PBKDF2

  • BCryptPasswordEncoder gibt uns BCrypt und

  • SCryptPasswordEncoder gibt uns SCrypt

Die Kennwortcodierer für PBKDF2, BCrypt und SCrypt unterstützen die Konfiguration der gewünschten Stärke des Kennwort-Hash.

Wir können diese Encoder direkt verwenden, auch ohne eine Spring Security-basierte Anwendung. Wenn wir unsere Site mit Spring Security schützen, können wir unseren gewünschten Passwort-Encoder über DSL oder überdependency injection konfigurieren.

Und im Gegensatz zu unseren obigen Beispielenthese encryption algorithms will generate the salt for us internally. Der Algorithmus speichert das Salt im Ausgabe-Hash für die spätere Verwendung bei der Validierung eines Kennworts.

7. Fazit

Wir haben uns also intensiv mit dem Passwort-Hashing befasst. Erkundung des Konzepts und seiner Verwendung.

Wir haben uns einige historische Hash-Funktionen sowie einige derzeit implementierte angesehen, bevor wir sie in Java codierten.

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

Wie immer lautet der Codeavailable on GitHub.