Passwörter niemals speichern
Teil des Abschnitts Authentifizierung und Sicherheit der Node.js-Journey von Coddy. Lektion 4 von 24.
Menschen verwenden Passwörter mehrfach, daher kann ein offengelegtes Passwort im Klartext auch Konten an anderer Stelle gefährden. Speichere einen gesalzenen Passwort-Hash: einen abgeleiteten Wert, den du überprüfst, indem du ihn neu berechnest, statt ihn zu entschlüsseln.
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');Dieses Beispiel kombiniert ein Salt und einen abgeleiteten Schlüssel für einen Einladungscode. Durch das Trennzeichen lässt sich bei der Überprüfung das Salt wiederherstellen und mit denselben Parametern ein weiterer Schlüssel ableiten. Bei deiner Passwortaufgabe werden ein eigenes Trennzeichen und eine eigene Schlüssellänge verwendet. Erzeuge für jedes neue Passwort ein Salt, leite den Schlüssel ab und speichere dann beide. Gesalzene Hashes erfordern dennoch starke Passwörter, da ein Angreifer mögliche Passwörter ausprobieren kann.
Aufgabe
EinfachZurzeit speichert die Registrierung jedes Passwort genau so, wie es eingegeben wurde. Sorge dafür, dass stattdessen ein gesalzener Hash gespeichert wird, damit ein Datenbankleck die Passwörter nicht preisgibt.
- Ändere in
passwords.jshashPassword(password), sodass die Funktion den Text zurückgibt, den die Registrierung speichert, und zwar in der Form Salz, Doppelpunkt, Hash:- Das Salz besteht aus 16 zufälligen Bytes, wird bei jedem Aufruf neu erzeugt und als Hexadezimalzahl geschrieben: 32 Zeichen von 0 bis 9 und von a bis f.
- Der Hash ist ein 64 Byte langer Schlüssel, den
scryptaus dem Passwort und diesem Salz erstellt und ebenfalls als Hexadezimalzahl schreibt: 128 Zeichen. Das dritte Argument vonscryptAsyncist die Schlüssellänge in Bytes. - Verbinde die beiden mit einem Doppelpunkt. Ein gespeicherter Wert sieht so aus:
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- Du musst
server.jsnicht ändern. Der Handler fürPOST /signupruft bereitshashPasswordauf und speichert den zurückgegebenen Wert. Außerdem gibt esGET /debug/users/:username, womit du sehen kannst, was für einen Benutzer gespeichert wurde. Diese Route gibt es nur, damit du nachsehen kannst; eine echte App hat sie nie.
Probier es aus: Drücke auf „Ausführen“. Sende POST /signup mit {"username": "ada", "password": "correct horse"}. Du erhältst den Status 201 und {"username": "ada"}. Sende denselben Body mit "username": "bob". Sende nun GET /debug/users/ada und danach GET /debug/users/bob. Jeder passwordHash besteht aus 32 Zeichen, einem Doppelpunkt und weiteren 128 Zeichen. Die beiden Werte sind unterschiedlich, obwohl ada und bob dasselbe Passwort gewählt haben.
Probier es selbst
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Wandelt ein Passwort in den Text um, den signup speichert.
// Vorerst bleibt das Passwort so, wie es eingegeben wurde.
export async function hashPassword(password) {
return password;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Authentifizierung und Sicherheit
1Passwörter
Bytes und Hex-TextEinen Passwortschlüssel ableitenEin neues SaltPasswörter niemals speichernSchlüssel-Bytes vergleichenEin Passwort überprüfenRegeln für die RegistrierungÜbe selbstständig: Express-Playground