Passwort-Speicher-Audit: Hashing, Salting und sichere Migration
Lerne, wie du ein Passwort-Speicher-Audit in übernommenem Code durchführst: prüfe Hashing, Salting und Peppering und upgrade die Hashes sicher beim nächsten Login.

Worauf ein Passwort-Speicher-Audit prüft (und warum es wichtig ist)
Gute Passwort-Speicherung bedeutet ganz einfach: Wenn jemand deine Benutzer-Datenbank stiehlt, darf er trotzdem diese Passwörter nicht nutzen können.
Deine App sollte Passwörter niemals im Klartext speichern. Stattdessen muss sie einen Einweg-Hash speichern, der langsam genug ist, um Ratenangriffe zu erschweren, einzigartig pro Nutzer ist und so aufgebaut ist, dass du ihn im Laufe der Zeit aufrüsten kannst.
Ein Passwort-Speicher-Audit prüft die ganze Kette, nicht nur den Login-Bildschirm. In übernommenem Code (besonders aus schnell generierten AI-Projekten) scheinen Logins oft zu funktionieren, während die Speicherung unsicher ist. Ein Prototyp könnte Passwörter mit einer schnellen Funktion hashen, denselben Salt wiederverwenden oder versehentlich Geheimnisse beim Debuggen loggen. Solche Probleme brechen den Happy-Path nicht, können aber ein Datenleck schnell in eine Welle von Account-Übernahmen verwandeln.
Wenn Angreifer schwache Passwort-Hashes erwischen, können sie offline-Rate-Angriffe starten. Sie müssen nicht deine Server treffen oder Ratenbegrenzungen auslösen — sie versuchen einfach lokal so lange Kombinationen, bis etwas passt. Ist ein Passwort geknackt, wird es oft auch auf anderen Diensten getestet, weil Nutzer Passwörter wiederverwenden.
Gute Passwort-Speicherung beinhaltet in der Regel:
- Einen modernen, langsamen Passwort-Hashalgorithmus (nicht einen allgemeinen Hash wie MD5 oder SHA-1).
- Einen einzigartigen, zufälligen Salt pro Passwort, der neben dem Hash gespeichert wird.
- Optionales Peppering: ein separates Geheimnis, das außerhalb der Datenbank gehalten wird.
- Klare Versionierung, damit du Einstellungen später ändern kannst, ohne Logins zu brechen.
- Keine unbeabsichtigte Offenlegung (Logs, Analytics-Events, Fehlermeldungen, Backups).
Die sicherste Reihenfolge ist: zuerst auditieren, dann migrieren. Das Audit identifiziert, was heute vorhanden ist (Algorithmus, Einstellungen, wo der Code liegt, wie Resets funktionieren), und danach wählst du einen Upgrade-Plan.
Ein verbreiteter Plan ist „Rehash beim nächsten Login“: Nutzer melden sich normal an, und wenn ein Passwort erfolgreich verifiziert wurde, aktualisierst du den gespeicherten Hash auf den neuen Standard.
Rote Flaggen, die du in übernommenem Code schnell findest
Du brauchst keinen kompletten Rewrite, um die größten Risiken aufzuspüren. Ein schnelles Audit beginnt oft mit einfachen Suchvorgängen, die zeigen, ob Passwörter unsicher gespeichert oder gehandhabt werden.
Die dringendste rote Flagge ist alles, was darauf hindeutet, dass Passwörter wiederherstellbar sind. Wenn du siehst, dass Passwörter direkt in einer Datenbankspalte gespeichert werden, in die Konsole geloggt, an Analytics gesendet oder mit etwas „verschlüsselt“ werden, das reversibel ist (z. B. AES mit gespeichertem Schlüssel), behandle das als Sicherheitsvorfall. Passwörter sollten nur als Einweg-Hashes gespeichert werden.
Ein weiteres häufiges Problem sind schnelle Hashes. Du könntest MD5, SHA-1 oder einfaches SHA-256 direkt auf das Passwort angewendet sehen. Auch wenn es „gehashed“ aussieht, sind schnelle Hashes dafür gebaut, schnell zu sein — und damit leicht in großem Maßstab zu knacken. Wenn der Code hash(password) sagt und sonst nichts, ist das ein starkes Indiz, dass kein richtiger Passwort-Hash verwendet wird.
Schnelle Checks, die viele der schlimmsten Probleme aufdecken:
- Erwähnungen von
md5,sha1,sha256(password)oder Helfermethoden wie „encryptPassword“. - Hash-Ausgaben, die immer dieselbe Länge und dasselbe Format haben, ohne Hinweis auf einen per-User Salt.
- Passwörter oder Reset-Tokens in Logs, Error-Reports oder Datenbank-Dumps.
- Geheimnisse (JWT-Keys, Datenbank-Passwörter,
PEPPER=...) hardcodiert im Repo oder in konfigurierten Dateien. - Login-Code, der nur ein Hash-Format annimmt und keinen Upgrade-Pfad hat.
Fehlender oder defekter Salt ist subtil, aber leicht zu erkennen, wenn du weißt, worauf du achten musst. Wenn zwei Nutzer dasselbe Passwort haben und dasselbe gespeicherte Ergebnis, benutzt das System wahrscheinlich keinen Salt, einen globalen Salt oder einen vorhersehbaren Salt. Eine gesunde Einrichtung erzeugt unterschiedliche gespeicherte Werte auch für identische Passwörter.
Ein praktisches Beispiel: Du übernimmst eine Node-App und findest eine users.password-Spalte voller 64-stelliger Hex-Strings. Der Login-Handler macht sha256(req.password) und vergleicht das mit dem Datenbankwert. Es „funktioniert“, ist aber verwundbar und gibt dir keinen sicheren Weg, die Sicherheit zu verbessern, ohne mehrere Hash-Formate einzuplanen.
Prüfe außerdem, ob der Login-Flow Änderungen unterstützen kann. Wenn der Code Legacy-Hashes nicht verifizieren und dann beim nächsten erfolgreichen Login mit einer stärkeren Methode rehashen kann, werden Upgrades riskant und können zu Lockouts führen.
Kartiere, wo Passwörter und Reset-Flows gehandhabt werden
Ein Audit geht schneller, wenn du mit einer einfachen Karte startest: jede Stelle, an der ein Passwort oder Reset-Token erstellt, gesendet, verarbeitet oder gespeichert wird. In übernommenem Code sind die riskanten Teile oft nicht in einem „auth“-Ordner. Sie sind über UI-Formulare, API-Routen, Background-Jobs und Admin-Tools verstreut.
Beginne damit, jeden Einstiegspunkt aufzulisten, an dem ein Passwort ins System gelangen kann, und bestätige jeden Ort im Code und in den Produktionskonfigurationen. Häufige Stellen sind Signup-Flows, Login (inklusive SSO-Fallbacks), Passwort-Reset und -Wiederherstellung, Admin-/Support-Tools sowie Importe oder Migrationen (CSV-Uploads, CRM-Syncs, Seed-Skripte).
Finde dann heraus, wo passwortbezogene Daten in der Datenbank liegen. Prüfe offensichtliche Spalten wie password, password_hash und hashed_password, aber auch Legacy-Tabellen und Schattenkopien (z. B. eine alte users_legacy-Tabelle, die noch von einem Background-Job gelesen wird). Wenn du mehr als ein Feld für Passwort-Hashes findest, notiere, welches davon tatsächlich beim Login verwendet wird.
Logging ist eine weitere übliche Leckstelle. Durchsuche Code und Monitoring-Konfigurationen nach allem, was sensible Werte erfassen könnte: Request-Logs, Analytics-Events, Error-Reports und Debug-Ausgaben. Ein realistischer Fehlerfall: Ein Login-Failure-Handler loggt den kompletten Request-Body „zur Fehlerbehebung“ und schickt so heimlich Klartext-Passwörter in Logs.
Passwort-Resets verdienen eine eigene Mini-Karte, weil Tokens leicht falsch gehandhabt werden. Identifiziere, wie Reset-Tokens erzeugt werden (Quelle der Zufälligkeit), wo sie gespeichert werden (Datenbankzeile, Cache, Payload im E-Mail-Link) und wie sie ablaufen. Prüfe auch, ob Tokens einmalig sind und was passiert, wenn ein Token nach Passwortänderung erneut verwendet wird.
Zeichne schließlich die Service-Grenzen: Notiere jedes Bauteil, das mit Auth zu tun hat: Client-Frontend, API-Gateway, Auth-Service, Background-Worker (E-Mail, SMS) und Drittanbieter-Identity-Provider. In AI-generierten Projekten findet man oft zusätzliche Auth-Endpunkte, die während Iterationen liegen geblieben sind — schließe alte Routen und deaktivierte Feature-Flags in deinen Scan ein.
Verifiziere den Hash-Algorithmus und seine Einstellungen
Ein Passwort-Speicher-Audit beginnt mit einer einfachen Frage: Verwendest du eine für Passwörter gedachte Hash-Funktion oder einen allgemeinen Hash?
Wenn du MD5, SHA-1, SHA-256 oder irgendetwas, das als „encrypt password“ bezeichnet ist, findest, behandle es als ernstes Problem. Diese Werkzeuge sind nicht dafür gemacht, Angreifer zu verlangsamen.
Bevorzuge dedizierte Passwort-Hashes wie Argon2id, bcrypt oder scrypt. Sie sind dafür gebaut, schwer zu knacken zu sein, sodass geleakte Hashes schwerer in echte Passwörter umzuwandeln sind.
Wie du anhand des gespeicherten Hashes erkennst, was du hast
Die meisten Systeme speichern Algorithmus und Einstellungen im Hash-String, sodass ein kurzer Blick auf einen Datenbankwert schon viel verrät.
Gängige Muster:
- Argon2id beginnt oft mit
$argon2id$und enthält Memory- und Iterations-Parameter. - bcrypt beginnt oft mit
$2a$,$2b$oder$2y$und enthält eine Cost-Angabe wie10oder12. - scrypt kann
$scrypt$zeigen oder Parameter wieN,rundp, abhängig von der Bibliothek.
Wenn du einen festlängen Hex-String (z. B. 32 oder 64 Hex-Zeichen) ohne $-Trennzeichen siehst, kann es sich um einen allgemeinen Hash handeln oder um ein individuelles Schema, das tiefer geprüft werden muss.
Prüfe die Einstellungen, nicht nur den Namen
Die Wahl des Algorithmus ist nur die halbe Geschichte. Argon2id kann schwach sein, wenn wenig Memory verwendet wird. bcrypt kann schwach sein, wenn der Cost zu niedrig ist.
Suche danach, wo der Work-Factor gesetzt wird und ob du ihn ohne Redeploy ändern kannst. Gesündere Setups halten Cost-Einstellungen in der Konfiguration, verwenden die eingebaute Verify-Methode der Bibliothek (nicht einen manuellen String-Vergleich) und vergleichen in konstanter Zeit.
Bestätige außerdem, dass der Login-Endpunkt grundlegende Abwehrmaßnahmen hat: Ratenbegrenzung pro Account und pro IP sowie sinnvolle Sperrregeln. Kurze, temporäre Sperren sind meist sicherer als permanente.
Prüfe das Salting: Einzigartigkeit, Speicherung und Zufälligkeit
Ein Audit sollte eine Regel bestätigen: Jeder Passwort-Hash muss seinen eigenen, einzigartigen, zufälligen Salt haben.
Wenn zwei Nutzer dasselbe Passwort wählen, sollten die gespeicherten Hashes trotzdem unterschiedlich aussehen. Wenn sie übereinstimmen, stimmt etwas nicht.
Einzigartigkeit: ein Salt pro Passwort, ohne Ausnahmen
Salts verhindern, dass Angreifer vorkalkulierte Tabellen nutzen und erschweren das Bulk-Cracking. Das funktioniert nur, wenn Salts nicht wiederverwendet werden.
Ein häufiges Problem in übernommenem Code ist ein einziger hartkodierter Salt in einer Config-Datei oder ein „Default“-Salt, der für alle Nutzer wiederverwendet wird. Ein schneller Sanity-Check ist, eine kleine Stichprobe gespeicherter Passwort-Hashes (20–50) zu ziehen und zu prüfen, ob sie denselben Salt-Abschnitt teilen oder ein sich wiederholendes Präfix zeigen. Findest du Wiederholungen, behandle das als Sicherheitslücke.
Speicherung: im Hash eingebettet vs. separate Spalte
Viele moderne Formate speichern den Salt im Hash-String selbst. Zum Beispiel enthalten bcrypt- und Argon2-Hashes typischerweise Algorithmus, Kostenparameter, Salt und Hash in einem Feld. Das ist normal.
Manche Systeme speichern den Salt in einer separaten Datenbankspalte neben dem Hash. Das kann ebenfalls in Ordnung sein, solange er wirklich per-User und nicht nullable oder auf einen gemeinsamen Wert defaultet ist. Das Risiko bei separaten Spalten sind unbeabsichtigte Wiederverwendungen durch Migrationen, ORM-Defaults oder Seed-Skripte.
Praktische Checks, die die meisten Probleme aufdecken:
- Bestätige, dass jeder Nutzer einen anderen Salt-Wert hat (oder einen unterschiedlichen eingebetteten Salt im Hash-String).
- Bestätige, dass Salts beim Setzen oder Zurücksetzen eines Passworts generiert werden, nicht beim App-Start.
- Stelle sicher, dass die Salt-Länge den Erwartungen des Algorithmus entspricht.
- Achte darauf, dass der Code eine kryptographisch sichere Zufallsquelle verwendet.
- Vermeide eigene „Salt-Formate“, die Strings manuell zusammensetzen.
Zufälligkeit ist genauso wichtig wie Einzigartigkeit. Wenn der Salt aus vorhersehbaren Quellen stammt (Timestamps, Nutzernamen, inkrementelle IDs), können Angreifer ihn erraten.
Ein realistischer Fehler in AI-generierten Prototypen ist ein Helfer wie salt = Math.random().toString(36) oder ein fixer SALT="abc", der über Dateien kopiert wurde. Das sieht zufällig aus, ist es aber nicht.
Wenn du ändern musst, wie Salts generiert oder gespeichert werden, mache es so, dass bestehende Nutzer normal weiter einloggen können und upgrade ihre Hashes sicher beim nächsten erfolgreichen Login.
Entscheide über Peppering und wie das Geheimnis sicher gespeichert wird
Ein Pepper ist ein geheimer Wert, der vor dem Hashing an das Passwort angehängt wird. Anders als ein Salt (einzigartig pro Nutzer und in der DB) ist der Pepper über viele Nutzer gemeinsam und sollte nur auf dem Server liegen.
Peppering hilft vor allem, wenn du eine Datenbank-Leak befürchtest und Offline-Cracking verhindern willst. Es ist besonders nützlich in übernommenen Apps, bei denen du nicht sicher bist, was generiert wurde oder ob Geheimnisse schon exponiert sind.
Peppering kann nach hinten losgehen, wenn du es wie eine normale Config-Bezeichnung behandelst. Leakt der Pepper (hardcodiert im Repo, in Logs gedruckt, in eine Client-App kopiert), bringt er wenig und erhöht das Risiko. Außerdem kann ein Deploy, das den Pepper entfernt oder ändert, Ausfälle verursachen: plötzlich kann sich niemand mehr einloggen.
Speichere den Pepper wie ein echtes Geheimnis:
- Halte ihn aus der Datenbank und aus dem Source-Control heraus.
- Lade ihn aus Umgebungsvariablen oder einem Secrets-Manager deiner Hosting-Umgebung.
- Begrenze den Zugriff auf die kleinen Gruppen von Personen und Diensten, die ihn brauchen.
- Sende ihn niemals an den Browser oder eine mobile App.
- Vermeide alles, was ihn teilweise in Logs offenlegen könnte.
Plane eine Rotation, bevor du ihn in Produktion nimmst. Das Rotieren eines Peppers ist schwieriger als das Rotieren eines API-Keys, weil es jede Passwort-Überprüfung beeinflusst.
Der sicherste Ansatz ist Dual-Pepper-Support für eine Übergangszeit: akzeptiere sowohl den alten als auch den neuen Pepper und upgrade Nutzer schrittweise. Beim Login verifizierst du zuerst mit dem neuen Pepper. Wenn das fehlschlägt, versuchst du den alten. Wenn der alte funktioniert, rehashst du und speicherst mit dem neuen Pepper. So gelingt die Rotation ohne erzwungene Passwort-Resets.
Schreibe auf, wer den Pepper sehen oder ändern darf, wo er in jeder Umgebung gesetzt ist und welchen Rollback-Plan es gibt, falls ein Deploy Logins bricht.
Schritt für Schritt: sichere Migration der Hashes beim nächsten Login
Ein sicherer „Rehash beim nächsten Login“-Plan lässt dich bestehende Passwörter akzeptieren und die Speicherung upgraden, ohne massenhaft Resets zu erzwingen. Das ist eine der wirkungsvollsten Maßnahmen, weil sie das Risiko schnell reduziert, ohne Nutzer zu unterbrechen.
1) Erkenne, ob ein gespeicherter Hash legacy oder modern ist
Mach den Datenbankwert selbstbeschreibend. Die meisten Passwort-Hash-Formate sind das bereits. Beispielsweise beginnen bcrypt-Hashes oft mit $2a$ oder $2b$, und Argon2-Hashes mit $argon2id$.
Hat dein Legacy-System etwas Eigenes verwendet (z. B. sha1(salt+password)), füge eine explizite hash_version-Spalte hinzu, damit du weißt, was zu verifizieren ist.
2) Verifiziere nur mit der Legacy-Methode, wenn nötig
Beim Login prüfst du zuerst das gespeicherte Format/die Version. Ist es modern, verifizierst du normal. Ist es legacy, rufst du nur den Legacy-Verifizierer für diesen Nutzer auf.
Achte auf „Double Hashing“ (das Passwort vor der Verifizierung nochmals hashen). Sorge dafür, dass der Verifizierer den rohen Passwort-String genau einmal erhält.
3) Rehash mit dem neuen Algorithmus und überschreibe bei Erfolg
Wenn die Legacy-Verifizierung erfolgreich ist, rehashst du sofort mit deiner neuen Wahl und aktuellen Einstellungen (z. B. Argon2id oder bcrypt mit stärkerem Cost) und schreibst das Ergebnis im modernen Format zurück.
Halte das Update atomar und an die User-ID gebunden, damit zwei Logins nicht in Konflikt geraten. Ein einfacher Ansatz ist: "zuerst verifizieren, dann Hash und hash_version in einem Schreibvorgang updaten".
if verify(password, stored_hash, version) == true:
new_hash = hash_new(password)
update users set password_hash = new_hash, hash_version = \"v2\" where id = user_id
allow_login()
else:
deny_login()
Konkretes Beispiel: Du übernimmst einen Prototyp, der unsalted SHA-1 plus ein globales Geheimnis verwendet hat. Diesen Verifier behältst du nur, um alte Accounts zu validieren. Nach dem ersten erfolgreichen Login wird die Zeile zu Argon2id upgraded und zukünftige Logins verwenden SHA-1 nie wieder.
4) Füge Observability hinzu, ohne Geheimnisse zu leaken
Verfolge Fortschritt und Probleme, aber logge niemals Passwörter oder komplette Hashes. Logge nur sichere Zähler und Ergebnisse, z. B. "legacy logins succeeded (rehash happened)", "legacy logins failed", "modern logins succeeded/failed", Anzahl der Nutzer noch im Legacy-Format und Rehash-Fehler (Schreibfehler, Versionskonflikt).
Häufige Migrationsfehler, die Nutzer aussperren
Ein Hash-Upgrade sollte für Nutzer unsichtbar sein. Die meisten Lockouts passieren, wenn die Migration Verhalten ändert, nicht Sicherheit.
Ein großer Fehler ist, Passwort-Resets zu erzwingen ohne Plan. Wenn du alle bestehenden Hashes ungültig machst, sind Leute, die keinen Zugriff mehr auf ihre alte E-Mail haben (oder die SSO nutzen), blockiert. Selbst bei notwendigen Resets nach einem Leak brauchst du einen Fallback, klare Kommunikation und Support für Randfälle wie nicht verifizierte E-Mails.
Ein weiterer häufiger Fall ist das Rehashen bei fehlgeschlagenen Login-Versuchen. Bei einem falschen Passwort kennst du nicht den richtigen Klartext, also kannst du nichts sicher rehashen. Schlimmer ist Code, der den gespeicherten Hash mit Müll überschreibt, der aus der falschen Eingabe abgeleitet wurde — das sperrt Nutzer aus, selbst wenn sie später das richtige Passwort eingeben.
Passwort-Normalisierungen können Logins ebenfalls stillschweigend brechen. Kleine Unterschiede wie das Trimmen von Leerzeichen, geänderte Case-Regeln oder verändertes Unicode-Handling können dazu führen, dass dasselbe eingegebene Passwort anders gehasht wird als zuvor. Ein realistisches Beispiel: Eine übernommene App hat während der Registrierung trailing spaces getrimmt, beim Login aber nicht. Nach einem Rewrite wurden beide Seiten vereinheitlicht, und einige Nutzer, die absichtlich ein trailing space nutzten, konnten sich nie wieder anmelden.
Achte außerdem auf gleichzeitige Logins und Race-Conditions beim Rehash. Wenn zwei Geräte gleichzeitig einloggen, könnten beide versuchen, den Hash zu upgraden. Wenn dein Update nicht atomar ist, überschreibt die eine Anfrage die andere oder schlägt fehl und hinterlässt einen inkonsistenten Account.
Eine kurze Checkliste, um Lockouts zu vermeiden:
- Rehash nur nach erfolgreicher Passwort-Überprüfung.
- Halte die Normalisierungsregeln während der Migration exakt gleich.
- Speichere den Pepper nur serverseit, nie im Client-Code.
- Mache das Hash-Update atomar (ein Schreibvorgang, geschützt durch den erwarteten aktuellen Hash).
- Logge und warne über Migrationsfehler, ohne gültige Logins zu blockieren.
Schnelle Checks, bevor du die Änderungen auslieferst
Bevor du Passwort-Arbeit in Produktion bringst, mache einen praktischen Durchlauf, der Fehler aufdeckt, die Nutzer sofort merken: fehlerhafte Logins, kaputte Resets und unbeabsichtigte Leaks in Logs.
Teste Login- und Rehash-Flows mit unordentlichen, realen Eingaben. Verlasse dich nicht auf einen einzigen Happy-Path-Account. Probiere sehr lange Passwörter (200+ Zeichen), Unicode, alte Accounts, die seit Monaten nicht mehr eingeloggt waren, und Nutzer, die über verschiedene Wege erstellt wurden (Signup, Admin-Import, OAuth dann Passwort-Set). Bestätige, dass "falsches Passwort"-Fehler generisch und konsistent sind und nicht verraten, ob ein Konto existiert.
Passwort-Resets verdienen eigene Tests, weil übernommener Code oft Tokens im Klartext speichert. Behandle Reset-Tokens wie Passwörter: speichere nur einen Hash des Tokens und vergleiche, indem du das eingegebene Token ebenfalls hashst. Verifiziere, dass Tokens ablaufen, nach Gebrauch ungültig werden und nicht replaybar sind. Ein einfacher Test: Fordere zwei Resets nacheinander an, nutze das erste Token und bestätige, dass das zweite danach abgelehnt wird.
Schicke nichts ohne Rollback-Plan. Mach ein frisches Backup und schreibe genau auf, wie du zurückdrehst, falls Logins explodieren oder der Support überschwemmt wird. Bestätige auch, dass dein "Rehash beim nächsten Login"-Update sicher ist, wenn es halbwegs fehlschlägt (z. B. Passwort verifiziert, aber Schreibvorgang in der DB schlägt fehl). Nutzer sollten sich beim nächsten Versuch weiterhin einloggen können.
Führe abschließend einen Basis-Abuse-Check durch. Setze Ratenbegrenzungen für Login- und Reset-Endpunkte und stelle sicher, dass verdächtige Muster markiert werden (viele Versuche, viele Reset-Anfragen, wiederholte Fehler von einer IP). Überprüfe Logs und Error-Tracking ebenfalls — sie dürfen niemals rohe Passwörter, Reset-Tokens oder komplette Authorization-Header enthalten, auch nicht im Debug-Modus.
Nächste Schritte: Audit durchführen und übernommene AI-built Apps härten
Wenn du eine AI-generierte App übernommen hast, behandle Auth wie das, was dir am schnellsten schaden kann. Ein Passwort-Speicher-Audit ist meist der schnellste Weg, Probleme zu finden, die zu Account-Übernahmen führen.
Ein typisches Muster ist ein Prototyp mit Flickwerk-Auth: schwache Hash-Einstellungen, hardcodierte Geheimnisse und ein Reset-Flow, der missbraucht werden kann. Die App sieht in einer Demo gut aus, ist aber nicht production-ready.
Priorisiere sinnvoll: Entferne zuerst exponierte Geheimnisse, blockiere unsichere Fallback-Login-Logik und behebe offensichtliche Injektionspfade rund um Auth-Endpunkte. Migriere dann die Nutzer schrittweise, damit du keine Massen-Resets erzwingst.
Wenn du einen Experten willst, der schnell überprüft und repariert, hilft es, Repo-Zugang (oder einen sauberen Export), den Branch, den du deployen willst, eine Möglichkeit, die App lokal zu starten (Env-Variablen, Test-DB), ein paar Test-Accounts (inkl. einem Legacy-Account, falls du alte Hashes hast) und Hinweise, wo Geheimnisse heute liegen (Hosting-Config, Env-Dateien, CI-Einstellungen) bereitzustellen.
Wenn du mit einer übernommenen, AI-generierten Codebasis arbeitest und nicht sicher bist, was wirklich gespeichert ist, kann FixMyMess (fixmymess.ai) AI-erstellte Apps diagnostizieren und reparieren, inklusive Auth-Logik, Geheimnis-Handling und sicherer "Rehash-on-next-login"-Migrationen. Sie bieten ein kostenloses Code-Audit an, um Probleme zu identifizieren, bevor du committest, und die meisten Projekte sind innerhalb von 48–72 Stunden erledigt.
Ein klares "Done"-Ziel hält die Arbeit fokussiert:
- Neue Passwörter verwenden immer den genehmigten Hash und die richtigen Einstellungen.
- Erfolgreiche Logins upgraden Legacy-Hashes automatisch.
- Reset- und Change-Password-Flows sind getestet und rate-limitiert.
- Keine Klartext-Passwörter, keine reversible Verschlüsselung, keine exponierten Geheimnisse.
- Die Anzahl der Legacy-Hashes geht gegen Null, während aktive Nutzer sich einloggen.
Wenn du deine aktuelle Hash-Methode benennen kannst, aber nicht deren Einstellungen kennst, oder du nicht weißt, wie viele Nutzer noch Legacy-Hashes haben, ist das ein Zeichen, vor dem nächsten Release zu pausieren und ein Audit zu machen.
Häufige Fragen
What is a password storage audit actually trying to prove?
Du prüfst, ob ein gestohlener User-Datenbestand einem Angreifer erlauben würde, echte Passwörter wiederherzustellen. Gute Speicherung verwendet einen langsamen, einseitigen Passwort-Hash mit einem einzigartigen Salt pro Nutzer und vermeidet das Leaken von Geheimnissen über Logs, Backups oder Reset-Flows.
Außerdem wird kontrolliert, ob du im Laufe der Zeit sicher upgraden kannst, damit du nicht dauerhaft an einem schwachen Schema festhängst.
Why is using MD5 or SHA-256 for passwords considered unsafe?
Schnelle Hashes wie MD5, SHA-1 oder schlichtes SHA-256 sind dafür gebaut, schnell zu sein — genau das, was Angreifer für Offline-Raten nutzen wollen. Wenn eine Datenbank geleakt wird, können sie Milliarden von Versuchen auf ihren eigenen Maschinen durchführen, ohne eure Server zu belasten.
Dedizierte Passwort-Hashes (z. B. Argon2id, bcrypt oder scrypt) sind so ausgelegt, dass das Erraten teuer wird, dadurch sind geleakte Hashes deutlich schwerer in echte Passwörter umzuwandeln.
How can I tell what hashing method my app is using?
Schau dir das gespeicherte Passwortformat und den Code an, der es verifiziert. Viele moderne Formate sind selbsterklärend und beginnen mit Markern wie $argon2id$ oder $2b$ (bcrypt).
Wenn du fixe Hex-Strings siehst (z. B. 32 oder 64 hex Zeichen) und der Login-Code etwas wie sha256(password) macht, bevor er vergleicht, ist das ein klarer Hinweis darauf, dass kein richtiger Passwort-Hashing-Mechanismus verwendet wird.
What does “unique salt per user” mean, and how do I spot bad salting?
Ein Salt muss für jedes Passwort einzigartig und zufällig sein. Seine Aufgabe ist, identische Passwörter unterschiedlich aussehen zu lassen, damit Angreifer nicht viele Nutzer mit der gleichen Arbeit knacken können.
Wenn zwei Nutzer mit demselben Passwort denselben gespeicherten Wert haben, benutzt ihr wahrscheinlich kein Salt, einen geteilten globalen Salt oder einen vorhersehbaren Salt — das ist ein ernstes Risiko.
Should I use a pepper, or is salting enough?
Ein Pepper ist ein geheimer Wert, der vor dem Hashing an das Passwort angehängt wird. Im Gegensatz zum Salt (einzigartig pro Nutzer und in der DB gespeichert) ist der Pepper über viele Nutzer gemeinsam und sollte nur auf dem Server liegen.
Ein Pepper hilft, wenn du eine Datenbank-Leak fürchtest, weil Angreifer zusätzlich den Pepper brauchen, um Offline-Versuche zu verifizieren. Nutze einen Pepper nur, wenn du ihn sicher speichern und stabil halten kannst — Verlust oder Änderung kann sonst alle Logins blockieren, außer du planst eine sorgfältige Rotation.
Where do password leaks happen besides the database column?
Lecks verstecken sich oft an unerwarteten Stellen: Request-Logs, Debug-Ausgaben in Error-Handlern, Analytics-Events oder Support-/Admin-Tools, die Eingaben zu Debug-Zwecken loggen.
Ein praktisches Audit durchsucht Code und Monitoring-Konfigurationen nach allem, was Login-Anfragen, Reset-Tokens oder Autorisierungsheader aufnehmen könnte.
What should I check in the password reset flow?
Reset-Tokens werden oft zu sorglos behandelt und landen im Klartext. Wenn jemand Zugriff auf die Datenbank oder Logs hat, kann er diese Tokens verwenden, um Konten zu übernehmen.
Sichere Muster: speichere nur einen Hash des Reset-Tokens, setze kurze Ablaufzeiten, mache Tokens einmalig und stelle sicher, dass ältere Tokens nach Passwortänderung ungültig werden.
What is “rehash on next login,” and why is it the safest migration?
Bewahre bestehende Logins, und verbessere die Speicherung genau dann, wenn du es kannst. Bei einem erfolgreichen Login verifizierst du ggf. noch mit der alten Methode, rehashst das Passwort sofort mit dem neuen Algorithmus und überschreibst den gespeicherten Wert.
So vermeidest du eine Massen-Zurücksetzung und bringst aktive Nutzer schrittweise in das stärkere Format.
What are the most common mistakes that cause lockouts during a hash upgrade?
Rehashen bei fehlgeschlagenen Versuchen ist ein häufiger Fehler: du weißt dann nicht das richtige Klartext-Passwort und kannst den gespeicherten Hash mit Müll überschreiben, wodurch Nutzer ausgesperrt werden. Auch Änderungen an Normalisierungsregeln (z. B. Trimmen von Leerzeichen, andere Unicode-Regeln) können dazu führen, dass dasselbe eingegebene Passwort anders gehasht wird.
Race-Conditions sind ebenfalls gefährlich, wenn zwei Logins gleichzeitig versuchen, den Hash zu upgraden; mache das Update atomar, damit das Konto konsistent bleibt.
How does this differ when the codebase was generated quickly by AI tools?
AI-generierte Prototypen haben oft Auth, die in einer Demo funktioniert, aber unsicher speichert: schnelle Hashes, hardcodierte Geheimnisse, versehentliches Loggen oder übrig gebliebene Endpunkte aus Iterationen. Ein schneller Gewinn ist ein Audit, das alle Eintrittspunkte für Passwörter und Tokens kartiert und dann die riskantesten Teile zuerst behebt.
Wenn du nicht sicher bist, was tatsächlich gespeichert ist oder wo Geheimnisse liegen, kann FixMyMess (fixmymess.ai) ein kostenloses Code-Audit machen und typischerweise Fixes in 48–72 Stunden liefern, inklusive sicherer Migrationen, die Logins nicht kaputtmachen.