Speichern Sie Passwörter mit Argon2id, konfiguriert mit mindestens 19 MiB Speicher, 2 Iterationen und 1 Grad an Parallelität, jeweils mit einem eindeutigen Salt pro Passwort. Das ist die Mindestkonfiguration im OWASP Password Storage Cheat Sheet. Wenn Ihre Datenbank noch MD5-, SHA-1- oder ungesalzene Hashes enthält, können Sie das beheben, ohne ein Massen-Reset der Passwörter auszulösen und ohne schwache Hashes für inaktive Konten zurückzulassen.
Was Sie verwenden sollten, und die Mindesteinstellungen
Das Cheat Sheet nennt diese Mindestwerte:
| Situation | Algorithmus | Mindesteinstellungen |
|---|---|---|
| Empfohlen | Argon2id | 19 MiB Speicher, 2 Iterationen, Parallelität 1 |
| Argon2id nicht verfügbar | scrypt | Kostenparameter 2^17, Blockgröße 8, Parallelität 1 |
| Legacy-Systeme mit bcrypt | bcrypt | Work Factor 10 oder höher, Passwortlimit von 72 Byte |
| FIPS-140-Konformität erforderlich | PBKDF2 | 600.000 oder mehr, HMAC-SHA-256 |
Argon2id ist die primäre Variante in RFC 9106, und jede Implementierung dieses Dokuments muss sie unterstützen. Sie arbeitet in der ersten Hälfte des ersten Durchlaufs über den Speicher wie Argon2i und im restlichen Verlauf wie Argon2d.
Das 72-Byte-Limit von bcrypt
Das Cheat Sheet legt für bcrypt ein Passwortlimit von 72 Byte fest. Die Quellen sagen nicht, wie einzelne Bibliotheken mit längeren Eingaben umgehen, also testen Sie Ihre. Hashen Sie ein Passwort aus 72 Zeichen a gefolgt von b und prüfen Sie anschließend 72 Zeichen a gefolgt von c. Wenn die Verifikation erfolgreich ist, kürzt Ihre Bibliothek stillschweigend.
Begrenzen Sie dann entweder die Passwortlänge in Ihren Formularen auf 72 Byte und weisen Sie darauf hin, oder planen Sie den Umstieg auf Argon2id. RFC 9106 erlaubt Passwörter mit bis zu 2^32-1 Byte.
Warum schnelle Hashes versagen
MD5 und SHA-1 wurden auf Geschwindigkeit ausgelegt, und SHA-256 ist aus demselben Grund ungeeignet: Es erlaubt Angreifern, in kurzer Zeit sehr viele Versuche durchzuführen. Der Angreifer hasht Kandidaten aus geleakten Passwortlisten, Wörterlisten oder per Brute Force und vergleicht die Ergebnisse mit Ihren Datensätzen. GPUs und gemietete Cloud-Server machen das günstig.
Ein eindeutiger Salt zwingt den Angreifer, Hashes einzeln zu knacken. Er macht außerdem Rainbow Tables wirkungslos, und identische Passwörter erzeugen keine identischen Hashes mehr. RFC 9106 empfiehlt für das Passwort-Hashing einen Salt von 16 Byte. Ausgereifte Bibliotheken erzeugen und speichern den Salt für Sie, schreiben Sie diesen Teil also nicht von Hand.
Den Work Factor abstimmen
Es gibt keine universelle Zahl. Sie hängt von Ihrem Server und Ihrer Nutzerzahl ab, und Sie ermitteln sie per Experiment auf der Hardware, die Sie tatsächlich betreiben. Als Faustregel gilt, dass ein Hash weniger als eine Sekunde dauern sollte.
Ein zu hoher Wert hat seinen Preis. Jeder Anmeldeversuch verbraucht CPU-Zeit, und eine Flut von Versuchen kann den Server erschöpfen. Führen Sie Benchmarks unter realistischer Parallelität durch und wählen Sie einen Wert, den Sie bei Spitzenlast verkraften.
Prüfen Sie die Einheit, die Ihre Argon2-Bibliothek erwartet. RFC 9106 definiert die Speichergröße in Kibibyte, während das Cheat Sheet MiB angibt. 19 MiB entsprechen 19456 KiB, und wenn Sie 19 übergeben, obwohl die Bibliothek KiB erwartet, erhalten Sie 19 KiB Speicher. Diese Einstellung funktioniert, ist aber weit schwächer als beabsichtigt.
Der Work Factor wird typischerweise in der Hash-Ausgabe mitgespeichert. Das hilft bei der Migration, denn beim Login sehen Sie, mit welchen Parametern ein bestimmter Hash erzeugt wurde.
Pepper als zusätzliche Schicht
Ein Pepper ist ein Geheimnis, das für alle gespeicherten Passwörter gilt und außerhalb der Datenbank aufbewahrt wird, in einem Secrets-Vault oder einem HSM. Er hilft, wenn ein Angreifer nur die Datenbank erbeutet, etwa durch SQL Injection oder ein gestohlenes Backup. Für sich allein bringt er nichts, betrachten Sie ihn also als Defense in Depth.
Das Problem ist die Rotation. Ein kompromittierter Pepper lässt sich nicht ändern, ohne das Passwort jedes einzelnen Nutzers zu kennen. Ihn zu ersetzen erzwingt daher ein Reset für alle, die er geschützt hat. Klären Sie, wer für dieses Verfahren verantwortlich ist, bevor Sie einen Pepper einführen.
Alte Hashes upgraden
Das Cheat Sheet empfiehlt zur Erhöhung eines Work Factors, zu warten, bis sich der Nutzer das nächste Mal authentifiziert, und sein Passwort dann mit den neuen Einstellungen neu zu hashen. Der Wechsel von MD5-, SHA-1- oder ungesalzenen Hashes folgt derselben Logik, wobei diese Erweiterung von uns stammt.
- Kennzeichnen Sie jeden gespeicherten Hash mit seinem Algorithmus, entweder in einer separaten Spalte oder über das Hash-Format. Wenn Sie unsicher sind, was in der Tabelle steht, hilft Ihnen der Hash-Identifier, die Formate zu erkennen.
- Verifizieren Sie beim Login mit dem Algorithmus, den der gespeicherte Hash verwendet.
- Berechnen Sie bei Erfolg aus dem eingegebenen Passwort mit einem frischen Salt einen neuen Argon2id-Hash, sofern der Hash veraltet ist oder unter Ihren aktuellen Parametern liegt.
- Überschreiben Sie den alten Wert in derselben Operation.
ok = verify(row.scheme, row.hash, submitted)
if ok and (row.scheme != "argon2id" or needs_rehash(row.hash)):
row.hash = argon2id_hash(submitted) # fresh salt, current parameters
row.scheme = "argon2id"
save(row)
Inaktive Konten
Nutzer, die sich nie wieder anmelden, werden nie aktualisiert, sodass ihre schwachen Hashes unbegrenzt in der Tabelle liegen bleiben. Eine Lösung besteht darin, sie jetzt zu umhüllen. Wenden Sie Argon2id auf den vorhandenen MD5- oder SHA-1-Wert an, speichern Sie das Ergebnis mit einer Schemakennzeichnung wie argon2id(md5) und löschen Sie den bloßen Hash.
Beim Login berechnen Sie den Legacy-Hash des eingegebenen Passworts, verifizieren ihn gegen die Argon2id-Hülle und ersetzen die Hülle bei Erfolg durch einen einfachen Argon2id-Hash. Halten Sie genau fest, wie der Legacy-Wert kodiert ist (Hex oder Rohbytes), denn eine Abweichung lässt jeden Login für dieses Schema scheitern. Testen Sie den umhüllten Pfad zuerst an einer Kopie der Tabelle.
Das Umhüllen macht ein schwaches Passwort nicht stark. Es verhindert aber, dass eine gestohlene Tabelle mit MD5-Geschwindigkeit angegriffen werden kann.
Die Alternative ist, die alten Hashes nach einem Stichtag zu entfernen und bei der nächsten Anmeldung ein Zurücksetzen zu verlangen. Das Cheat Sheet beschreibt dies als Option, abhängig von der Anwendung. Wenn die Änderung eine Codebasis betrifft, die Sie nicht vollständig kontrollieren, kann unser Team für sichere Softwareentwicklung sie prüfen.
Wo Sie beginnen
- Auditieren Sie die Nutzertabelle: welche Algorithmen, ob Salts vorhanden sind und ob Passwörter im Klartext oder umkehrbar verschlüsselt gespeichert sind. Verschlüsselung ist nur zulässig, wenn Sie das ursprüngliche Passwort wiederherstellen müssen, und das Cheat Sheet rät, diese Notwendigkeit zu vermeiden.
- Wählen Sie Argon2id mit mindestens 19456 KiB, 2 Iterationen und Parallelität 1 und führen Sie Benchmarks auf der Produktionshardware durch, bis ein Hash unter einer Sekunde dauert.
- Wenn Sie bcrypt einsetzen, führen Sie den oben beschriebenen 72-Byte-Test durch und entscheiden Sie zwischen einer Längenbegrenzung und dem Umstieg auf Argon2id.
- Fügen Sie dem Schema eine Algorithmuskennzeichnung hinzu, ändern Sie den Login-Code so, dass er mit dem alten Schema verifiziert und bei Erfolg neu hasht.
- Umhüllen Sie die verbliebenen Legacy-Hashes mit Argon2id oder legen Sie einen Stichtag fest, nach dem sie entfernt werden und ein Zurücksetzen erforderlich ist.
- Wenn Sie einen Pepper einführen, speichern Sie ihn in einem Secrets-Vault und dokumentieren Sie zuvor das Verfahren für Rotation und erzwungenes Zurücksetzen.
