Passwort-Hashing in Java-Anwendungen richtig umsetzen!
24. März 2022
0 Min. LesezeitEs gibt verschiedene Möglichkeiten, sensible Passwörter zu speichern. Eine Auswahl zu haben, ist zwar gut – doch bei der Speicherung von Passwörtern kann die falsche Entscheidung zum Sicherheitsalbtraum werden. Sehen wir uns deshalb einige Ihrer Möglichkeiten an und hashen sie durch. In diesem Artikel erfahren Sie, wie Sie Passwörter in Ihren Java-Anwendungen hashen sollten. Diese Prinzipien lassen sich zwar auf jedes Ökosystem übertragen, wir zeigen Ihnen jedoch speziell, wie Sie Passwort-Hashing in Java am besten umsetzen.
Als Erstes sollten Sie sich bei der Entscheidung, wie Sie sensible Passwörter speichern, überlegen, ob Sie sich überhaupt selbst um die Authentifizierung und Autorisierung kümmern wollen. Es gibt zahlreiche Dienste, die Ihnen diese Aufgabe abnehmen. Wenn Sie einen Dienst für Authentifizierung und Autorisierung nutzen, müssen Sie Passwörter nicht mehr sicher in Ihrer Anwendung speichern. Kommerzielle Dienste wie Auth0 und Okta machen dies ganz einfach. Unterstützt Ihr Anbieter offene Standards wie OpenID Connect, können Sie ihn problemlos in Ihre Java-Anwendungen integrieren (zum Beispiel in Spring Boot). Außerdem unterstützt Ihr Anbieter möglicherweise auch MFA (Multi-Faktor-Authentifizierung), um die Sicherheit Ihrer Endnutzer weiter zu verbessern.
Wenn Sie Passwörter doch selbst in Ihrer Java-Anwendung speichern müssen, ist dieser Artikel genau das Richtige für Sie.
Passwörter für die Speicherung hashen
Wenn Sie Benutzernamen und Passwörter in Ihrer Anwendung speichern: Was auch immer Sie tun, speichern Sie Passwörter niemals im Klartext (ich weiß, ich weiß – das sollte selbstverständlich sein!). Wird Ihr System kompromittiert, kann ein Angreifer diese Klartextpasswörter einfach auslesen und sich als Benutzer ausgeben.
Um Passwörter nicht im gefürchteten Klartext zu speichern, sollten Sie stattdessen Hashes der Passwörter Ihrer Benutzer speichern. Dazu benötigen Sie einen Passwort-Hashing-Algorithmus.
Was ist ein Passwort-Hashing-Algorithmus?
Es gibt verschiedene Arten von Hashing-Algorithmen. Passwort-Hashing-Algorithmen sind jedoch Einwegfunktionen, die speziell für Passwörter entwickelt wurden. Sie wandeln ein Klartextpasswort in eine Datenzeichenfolge um, die Sie sicher in einer Datenbank speichern können und die sich nicht umkehren lässt. Sie können ein Klartextpasswort in einen Hash umwandeln, aber nicht einen Hash in ein Passwort – daher die Bezeichnung „Einwegfunktion“.
Wie funktioniert Passwort-Hashing?
Passwort-Hashing-Algorithmen kommen bei der Benutzerauthentifizierung zum Einsatz. Jedes Mal, wenn ein Benutzer Ihnen sein Passwort im Klartext sendet, wird es sofort gehasht. Anschließend wird der Hash entweder gespeichert (bei der Registrierung) oder mit dem gespeicherten Hash des Benutzers verglichen, um zu überprüfen, ob das Passwort korrekt ist (Authentifizierung).
Es gibt viele Hashing-Algorithmen, aber nur wenige eignen sich gut für Passwörter. Viele Hashing-Funktionen haben spezielle Anwendungsfälle, etwa die Überprüfung der Integrität einer Datei. Diese Algorithmen sind für Passwörter ungeeignet.
Für die Passwörter Ihrer Benutzer benötigen Sie einen starken Passwort-Hashing-Algorithmus. Ein guter Passwort-Hashing-Algorithmus beansprucht einen beträchtlichen Anteil an Rechenleistung und Speicher. Bei Passwort-Hashing-Algorithmen gilt: Je mehr Rechenressourcen sie benötigen, desto besser!
Starke Passwort-Hashing-Algorithmen sind langsam, wodurch Brute-Force-Angriffe weniger effektiv sind. Wir könnten hier noch viel tiefer ins Detail gehen, aber die Kurzfassung lautet: Verwenden Sie für Passwörter einen starken, ressourcenintensiven Passwort-Hashing-Algorithmus, damit Ihre Benutzer bestmöglich geschützt sind.
Was ist der beste Passwort-Hashing-Algorithmus?
Die erste Regel für Passwort-Hashing-Algorithmen lautet: Schreiben Sie niemals Ihren eigenen Passwort-Hashing-Algorithmus! Eine Ausnahme gilt, wenn Sie ein erfahrener Kryptograf sind. Andernfalls sollten Sie sich auf die Branchenstandards verlassen und geprüfte Algorithmen und Bibliotheken in Ihrer Anwendung verwenden.
Laut der OWASP Foundation kommen für modernes Passwort-Hashing nur wenige Algorithmen infrage. Sehen wir uns die empfohlenen Passwort-Hashing-Algorithmen an!
Argon2id
Derzeit (2022) ist Argon2id der beste Algorithmus. Argon2 ist eine Schlüsselableitungsfunktion, die als Gewinner der Password Hashing Competition ausgewählt wurde. Es gibt drei verschiedene Varianten:
Argon2d: maximiert den Schutz vor GPU-basierten Knackangriffen
Argon2i: optimiert für den Schutz vor Seitenkanalangriffen
Argon2id: eine hybride Variante
Für Passwörter wird Argon2id empfohlen, da es einen ausgewogenen Schutz vor Seitenkanal- und GPU-basierten Angriffen bietet. Sie können den Argon2id-Algorithmus mit drei Parametern konfigurieren: Speichergröße (m), Iterationsanzahl (t) und Parallelitätsgrad (p).
Derzeit wird empfohlen, Argon2id mit mindestens 15 MiB Speicher, 2 Iterationen und einem Parallelitätsgrad von 1 zu verwenden. Der Algorithmus fügt für jeden einzelnen Benutzer automatisch einen Salt hinzu, um Angriffe mit vorberechneten Hashes zu verhindern. Sie müssen dafür also nichts weiter tun.
Spring Security Crypto mit Bouncy Castle verwenden
Am einfachsten implementieren Sie Arong2id in Ihrer Java-Anwendung mit der Bibliothek spring-security-crypto. Sie ist zwar Teil des Spring-Frameworks, Sie müssen jedoch nicht den Rest des Spring-Frameworks verwenden.
Die Bibliothek spring-security-crypto bietet einen Argon2PasswordEncoder, den Sie verwenden können. Meiner Meinung nach ist der Name nicht ganz treffend, da es sich technisch gesehen nicht um einen Encoder, sondern um einen Hasher handelt. Die Spring-Bibliothek verwendet bouncycastle als Abhängigkeit. Diese enthält eine vollständige, in Java geschriebene Implementierung des Argon2-Algorithmus. Die Bibliothek spring-security-crypto lässt sich als intuitive Schnittstelle für bouncycastle verstehen, die die Verwendung vereinfacht. Zusätzlich zu bouncycastle benötigen Sie außerdem eine Abhängigkeit zu common-logging – Sie haben es erraten: zum Protokollieren.
Der Argon2PasswordEncoder verwendet standardmäßig die Argon2id-Variante mit m=4MiB, t=3 und p=1. Auch wenn die Iterationsanzahl über dem Mindestwert liegt, sollten Sie dennoch einen höheren Speicherverbrauch in Betracht ziehen. Im folgenden Java-Beispiel verwende ich die Mindestanforderungen m=15Mib, t=2 und p=1. Für die Salt- und Hash-Länge verwende ich dieselben Werte wie in den Standardeinstellungen.
Die Ausgabe dieses Codes sieht in etwa so aus:
Dieser Hash enthält alle erforderlichen Informationen, einschließlich der Einstellungen, die ich für den Encoder angegeben habe, sowie der Salt-Informationen. So können Sie mit encoder.matches() ganz einfach prüfen, ob das ursprüngliche Passwort übereinstimmt. Das funktioniert auch mit einer anderen Instanz von Argon2PasswordEncoder mit anderen Einstellungen.
Das Argon2 Binding für die JVM verwenden
Die Argon2 Binding-Bibliothek für die JVM ist eine Alternative zur Spring-Bibliothek. Sie wurde von Moritz Halbritter entwickelt und verwendet JNA, um eine native C-Bibliothek aufzurufen. Der Vorteil dieses Ansatzes ist, dass dabei die Originalimplementierung der Argon2-Autoren zum Einsatz kommt und möglicherweise eine höhere Leistung erzielt wird. Daher benötigen Sie Zugriff auf die zugrunde liegende C-Bibliothek auf Ihrem System.
Sie können diese C-Bibliothek entweder selbst mit Ihrem Paketmanager installieren oder eine Bibliothek verwenden, die vorkompilierte Argon2-Bibliotheken enthält. Die erste Möglichkeit wird aus dem naheliegenden Grund empfohlen, dass sie weniger Speicherplatz benötigt.
Ohne vorkompilierte Bibliotheken:
Mit vorkompilierten Bibliotheken:
Die Verwendung dieser Bibliothek ist ganz einfach. Im folgenden Codebeispiel sehen Sie ein Beispiel, das dem Spring-Beispiel mit denselben Mindestparametern entspricht.
scrypt
Wenn Sie Argon2id aus irgendeinem Grund nicht verwenden können, ist scrypt eine gute zweite Wahl. Ähnlich wie Argon2id ist scrypt ein starker Passwort-Hashing-Algorithmus, bei dem Sie verschiedene Kostenparameter konfigurieren können, um den Ressourcenverbrauch zu erhöhen.
Laut dem OWASP Password Cheat Sheet sollten Sie einen Mindestwert für den CPU-/Speicherkostenparameter (N), eine Mindestblockgröße (r) und einen Parallelisierungsparameter (p) festlegen. Die folgenden Optionen gelten als Mindestwerte:
N=2^16 (64 MiB), r=8 (1024 Bytes), p=1
N=2^15 (32 MiB), r=8 (1024 Bytes), p=2
N=2^14 (16 MiB), r=8 (1024 Bytes), p=4
N=2^13 (8 MiB), r=8 (1024 Bytes), p=8
N=2^12 (4 MiB), r=8 (1024 Bytes), p=15
Bitte beachten Sie, dass alle oben aufgeführten scrypt-Parameter gleich starke Passwort-Hashes ergeben. Die Beispiele zeigen lediglich, dass der scrypt-Algorithmus je nach den angegebenen Werten für N, r und p mehr CPU- oder Speicherressourcen nutzen kann. Meine Empfehlung unten zeigt die praktische Verwendung, die Sie der Einfachheit halber einfach kopieren und einfügen können.
Die Bibliothek spring-security-crypto unterstützt viele Algorithmen, darunter auch SCrypt. Sie können den SCryptEncoder genauso verwenden wie zuvor den Argon2Encoder. Im folgenden Beispiel habe ich den mittleren Vorschlag gewählt, um CPU- und Speicherverbrauch ausgewogen zu verteilen.
Ausgabe:
BCrypt verwenden
Wenn Argon2id und scrypt nicht verfügbar sind, ist BCrypt eine weitere gute Wahl. Wenn Sie BCrypt verwenden, sollte der Work-Factor-Parameter auf mindestens 10 gesetzt werden.
Sie können die Bibliothek spring-security-crypto ähnlich wie zuvor verwenden. Die Standard-Workload ist auf 10 eingestellt. Im folgenden Beispiel setzen wir sie jedoch auf 14 (ein angemessener Wert für 2022).
Je höher Sie den Work-Factor einstellen, desto stärker ist der Hash – allerdings werden für die Berechnung auch mehr CPU-Ressourcen und mehr Zeit benötigt. Auf meinem lokalen Rechner benötigt BCrypt bei einer Workload von 10 durchschnittlich etwa 89 ms. Bei einer Workload von 14 sind es durchschnittlich 1.033 ms. Das ist fast zwölfmal so lange. Dies ist keineswegs ein präziser Benchmark, zeigt aber die Auswirkungen eines höheren Work-Factors.
Best Practices für Passwort-Hashing
Wenn Sie Passwort-Hashing in Ihrer Anwendung implementieren müssen, sollten Sie einige Best Practices beachten.
Implementieren Sie Passwort-Hashing-Algorithmen niemals selbst – verwenden Sie stattdessen eine gut geprüfte Entwicklerbibliothek! Kryptografie ist ein komplexes Gebiet. Wenn Sie versuchen, einen gängigen Algorithmus selbst zu implementieren, kann vieles schiefgehen.
Da Computer jedes Jahr leistungsfähiger und schneller werden, müssen Passwort-Hashing-Algorithmen und ihre Parameter angepasst werden. Moderne Passwort-Hashing-Algorithmen setzen darauf, dass Sie als Entwickler festlegen, wie viele Ressourcen die Berechnung eines Hashs beanspruchen soll. Mit der Zeit müssen Sie diese Parameter aktualisieren. Um hier auf dem Laufenden zu bleiben, sollten Sie aktuelle Sicherheitsnachrichten und Trends verfolgen. Der Snyk Blog ist beispielsweise eine hervorragende Quelle für Informationen zu Sicherheit und aktuellen Trends.
Stellen Sie mit kostenlosen Tools wie Snyk sicher, dass Ihre Bibliotheken und Techniken geschützt sind, und erkennen Sie Sicherheitsprobleme in Ihrem Code proaktiv. Tools wie Snyk können Sicherheitsprobleme frühzeitig erkennen, Korrekturen vorschlagen und Ihnen zusätzliche Informationen bereitstellen. Mit der fortschreitenden technologischen Entwicklung sind sie entscheidend, um Ihre Codebasis langfristig sicher zu halten.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



