Da sind keine einzigen Fehler zu machen. Der Fehler liegt in deinen falschen Annahmen darüber wie man mit Passwörter umgeht.
Passwörter speichert man weder im plaintext, noch verschlüsselt. Man produziert einen Hash mit einer Key Derivation Function (KDF), den man mit den Parametern die man für den Hash und dem Passwort rekonstruieren kann. Das Ergebnis ist dass man das Passwort selbst gar nicht mehr und die Korrektheit eines Passwortes nur mit dem Hash kontrollieren kann.
Das
mit jedem Aufruf einen anderen Hash zurückgibt ist also ein Feature. Dies verhindert dass ein Angreifer sich mit sogenannten Rainbow Tables - die quasi Wörterbücher in denen steht welche Passwörter zu welchen Hashes korrespondieren - auf einen Angriff vorbereiten und somit Rechenleistung einsparen kann.
Gibt es eine "zuverlässigere" Seite, die zB. beschreibt:
und nicht wie auf der genannten keine oder falsche Infos?
Die Seite beschreibt es schon größtenteils korrekt, das einzige Problem sind ist dass die Beispiele Hashes mit == Vergleichen und deswegen anfällig für timing basierte side-channel Attacks sind.
produziert einen Hash. Ob ein Passwort zu diesem Hash korrespondiert prüfst du dann mit
zu nutzen ist *nicht* korrekt, es ist ein massiver Fehler.
Zum einen generiert die library von selbst einen zufälligen Salt, zum anderen ist sie auch in der Lage Passwörter gegen einen Hash zu prüfen. Du musst und solltest zu keinem Zeitpunkt den Salt anfassen. Zum anderen ist 500 eine viel zu niedrige Zahl an Iterationen für PBKDF2, da ist leider auch der default der Library schlecht gewählt. Du solltest dir überlegen wieviel Zeit du in Hashing investieren kannst und dann für dass kürzeste erlaubte Passwort die Anzahl der Iterationen soweit nach oben schrauben bis du diese Zeit erreichst. Um etwas konkreter zu werden: Django empfiehlt seit kurzem 100.000 Iterationen. Man sollte schauen dass man eher etwas darüber als darunter wählt.
Noch besser wäre es allerdings wenn du
passlib, speziell den
CryptContext verwenden würdest. Die Library hat eine sicherere API, die timing side-channel Attacken ausschliesst. Außerdem abstrahiert sie vom dem verwenden Algorithmus und dessen Parametern und du kannst diese somit recht einfach durch neuere ersetzen und existierende Hashes upgraden. Zumindest die Anzahl der Iterationen wirst du nämlich regelmäßig erhöhen müssen und auch pbkdf2 wird wahrscheinlich irgendwann prinzipiell als unsicher gelten. Darauf sollte man mit einer Konfigurationsänderung reagieren können.