Journal

Was Sie mitnehmen, wenn Sie einen Login-Provider verlassen

Ein Wechsel zwischen Login-Providern braucht keinen Passwort-Reset, wenn der Export die Hashes enthält. Was er enthalten muss und was EAuth importiert.

Was ein Login-Provider wert ist, erfahren Sie an dem Tag, an dem Sie ihn verlassen wollen. Enthält der Export die Passwort-Hashes Ihrer Nutzer, ziehen Sie sie um, und niemand merkt etwas. Enthält er sie nicht, bekommt jeder Ihrer Nutzer eine Mail „Bitte setzen Sie ein neues Passwort“ von einer Firma, von der er nie gehört hat, und ein Teil davon kommt nie zurück. Dieser Beitrag handelt von der ersten Art Export, denn diese gibt EAuth, und davon, worauf Sie achten sollten, bevor Sie sich irgendwo registrieren.

Warum der Hash genügt

Ein Passwort-Hash ist nicht das Passwort. Er ist das Ergebnis einer langsamen, gesalzenen Funktion, das der Provider statt des Passworts speichert, und er lässt sich nur auf eine Art verwenden: um einen Kandidaten zu prüfen. Gibt man ihn dem nächsten Provider, hat dieser genau das, was der alte hatte, nicht mehr, und prüft Passwörter auf dieselbe Weise dagegen. Das Passwort des Nutzers reist nie mit, und niemand erfährt es.

Deshalb hat ein Provider keinen Sicherheitsgrund, die Hashes zurückzuhalten. Er hat einen geschäftlichen.

Was der Export enthalten muss

Verlangen Sie eine Datei mit, pro Konto, der E-Mail-Adresse, der Angabe, ob sie bestätigt wurde, dem Anzeigenamen und dem Passwort-Hash in einer Standardform als String, die sagt, welche Funktion ihn erzeugt hat. Argon2id im PHC-String-Format sieht so aus: $argon2id$v=19$m=65536,t=3,p=2$...; bcrypt beginnt mit $2a$, $2b$ oder $2y$; scrypt und PBKDF2-SHA256 haben eigene Formen, etwa $scrypt$ und Djangos pbkdf2_sha256$. Ein Hash ohne seine Parameter ist nutzlos, die Form zählt also so viel wie die Bytes.

Ob die Adresse bestätigt wurde, zählt mehr, als es scheint. Ein Provider, der ein Konto als unbestätigt markiert erhält, sollte ihm nicht einfach vertrauen, und EAuth tut das nicht: mehr dazu unten.

Sie wollen auch den Rest des Kontos: zu welchen Organisationen eine Person gehört und mit welcher Rolle, offene Einladungen, welche Konten sich über den Identity Provider einer Firma statt mit Passwort anmelden, und die Zustimmungen, die jede Person Ihrer Anwendung gegeben hat. Zweite Faktoren sind die Ausnahme, und es lohnt sich zu wissen, warum, bevor Sie danach fragen: Ein Passkey ist bewusst an die Domain des Providers gebunden und würde nirgends sonst funktionieren, und ein TOTP-Secret richtet man besser neu ein, als es von einer Datenbank in eine andere zu kopieren. Nach einer Migration richten Nutzer ihren zweiten Faktor neu ein, egal wohin sie gehen.

Was EAuth exportiert

In der Konsole finden der Owner und die Admins einer Anwendung auf deren Seite Users den Button Export everything. Er lädt die Anwendung als eine JSON-Datei herunter: ihre Einstellungen, das Team, Webhooks, Organisationen mit Mitgliedern, Rollen, offene Einladungen und Single-Sign-on-Verbindung, die Zustimmungen und jedes Konto mit seinem Passwort-Hash, so wie er gespeichert ist. Secrets reisen nicht mit: nicht das Client Secret, nicht die Secrets zum Signieren der Webhooks, nicht die privaten Schlüssel der Single-Sign-on-Verbindungen. Das sind Credentials unseres Dienstes, nicht Ihre Daten.

Der Hash ist Argon2id im PHC-Format für alle, die sich bei uns angemeldet haben, oder der Hash, mit dem sie importiert wurden, falls nicht. Jedes Konto sagt ausserdem, ob seine Adresse bestätigt ist, ob es einen zweiten Faktor hat, wie viele Passkeys es hat und, bei Single-Sign-on-Konten, über welchen Identity Provider es sich anmeldet. Das ist die Liste der Leute, die Sie um eine neue Einrichtung bitten müssen, fertig, bevor Sie umziehen. Die AGB sagen das Wesentliche in einem Satz, 7.3: Hashes sind in ihrer ursprünglichen Form im Export, sodass Sie zu einem anderen Provider migrieren können, ohne Ihre Nutzer zu zwingen, ihre Passwörter zurückzusetzen. Gehen zu können, halten wir für ein Feature, nicht für ein Risiko.

Der Export einer einzelnen Person, für eine Anfrage nach Art. 15 oder 20 DSGVO, liegt auf der Seite dieser Person in der Konsole und enthält keine Credentials: was über die Person bekannt ist, nicht das, womit sich jemand als sie anmelden kann.

Was EAuth importiert

Die andere Richtung geht durch dieselbe Tür. Der Import nimmt ein JSON-Array oder eine CSV-Datei mit email, password_hash und optional display_name und email_verified, bis zu 100'000 Konten und 25 MB pro Datei, und erkennt Argon2id, bcrypt, scrypt und PBKDF2-SHA256 an der Form des Hashs. Eine Spalte, die das angibt, brauchen Sie also nicht. Die Konsole prüft zuerst die ganze Datei und zeigt, was sie gefunden hat, wie viele Konten in welchen Formaten; geschrieben wird nichts, bevor Sie bestätigen. Eine Datei mit einer fehlerhaften Zeile wird als Ganzes abgewiesen, mit Zeile und Grund, ebenso eine Zeile, deren Adresse bei Ihrer Anwendung schon ein Konto hat, denn eine halb importierte Nutzerbasis ist schlimmer als keine.

Importierte Konten melden sich ab dem Moment, in dem der Import fertig ist, mit ihrem alten Passwort an. Bei diesem ersten Login wird das Passwort neu mit Argon2id gehasht. Eine Nutzerbasis, die auf bcrypt ankommt, lässt bcrypt also Person für Person hinter sich, ohne dass jemand etwas tun muss. Die Konsole markiert die Konten, die noch auf ihrem importierten Hash sind. An Ihren Webhook geht bei einem Import nichts: Ihr System kennt diese Leute schon.

Zwei Ausnahmen. Ein Konto, das mit email_verified false oder ohne diese Spalte importiert wurde, wird beim ersten Login gebeten, seine Adresse zu bestätigen, bevor Ihre Anwendung es bekommt: Seit dem 3. Oktober bekommt keine Anwendung ein Konto, dessen Adresse niemand bestätigt hat, importiert oder nicht. Markieren Sie als verifiziert, was der alte Provider verifiziert hatte, und nicht mehr. Und ein Passwort, das kürzer als 12 oder länger als 256 Zeichen ist, meldet sich zwar weiterhin an, wird aber nicht neu gehasht, denn diese Längen liegen ausserhalb dessen, was EAuth für ein neues Passwort akzeptiert. Dieses Konto behält seinen importierten Hash, bis die Person das Passwort ändert, und die Markierung in der Konsole bleibt.

Eine Sache, die Sie über bcrypt wissen sollten

bcrypt nutzt nur die ersten 72 Bytes eines Passworts. Wer ein längeres hat, hat sich beim vorigen Provider mit diesen 72 Bytes angemeldet und tut das weiter bis zum ersten Login bei EAuth, wenn das ganze Passwort mit Argon2id gehasht wird. Eine kleine Verbesserung, um die niemand bitten muss, und ein Grund, sich nicht zu wundern, dass eine Passphrase mit 90 Zeichen vorher funktioniert hat und es immer noch tut.

Bevor Sie sich irgendwo registrieren

Lesen Sie die Export-Klausel der AGB vor der Feature-Liste. Schweigen die AGB zu Hashes, gehen Sie davon aus, dass die Antwort Nein lautet. Gibt es eine Klausel und sagt sie „auf Anfrage“ oder „nach Prüfung“, rechnen Sie mit einer Verzögerung von Wochen, genau dann, wenn Sie sie am wenigsten brauchen können. Die Klausel, die Sie wollen, sagt: jederzeit, ohne Nachfrage, in einem dokumentierten Format, Hashes inbegriffen.

Quellen

  1. Password Storage Cheat Sheet, OWASP, gelesen am
  2. PHC Strings, C2SP, gelesen am
  3. RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications, IETF, gelesen am

Geschrieben von Samuel Krauss, Founder. Abgelegt unter eauth, migration, passwords.

Übersetzt aus dem Englischen. Zum englischen Original

Alle Beiträge Dieser Beitrag als Markdown Atom-Feed