Ein Passwort überprüfen
Teil des Abschnitts Authentifizierung und Sicherheit der Node.js-Journey von Coddy. Lektion 6 von 24.
Bei einer Anmeldung wird aus dem eingegebenen Passwort mithilfe des gespeicherten Salt-Werts und der ursprünglichen Schlüssellänge ein Schlüssel abgeleitet. Ein neuer Salt-Wert würde selbst für das richtige Passwort einen anderen Schlüssel ergeben. Das ursprüngliche Passwort wird niemals aus dem Speicher decodiert.
// Ein Einladungscode wurde als salt.keyHex gespeichert
const [salt, keyHex] = savedInvite.split('.');
const expected = Buffer.from(keyHex, 'hex');
const attempted = await scryptAsync(inviteCode, salt, 32);Vergleiche die resultierenden Bytefolgen mit timingSafeEqual, nachdem du sichergestellt hast, dass ihre Längen übereinstimmen. Dadurch wird ein vom Inhalt abhängiger vorzeitiger Abbruch verhindert, der Informationen durch die Ausführungszeit preisgeben könnte. Bei Buffer prüft === die Identität, und ein normaler Zeichenfolgenvergleich bietet keine Garantie für eine konstante Ausführungszeit. Deine Passwortfunktion verwendet den Doppelpunkt als Trennzeichen im Passwortdatensatz und einen 64 Byte langen Schlüssel. Die von dir hinzugefügte Route POST /login verwendet das Ergebnis, um 200 oder 401 zurückzugeben.
Aufgabe
EinfachDieser Schritt öffnet das vorbereitete private Notes-API-Projekt des Kurses und nicht deine Projektdateien aus Passwörter niemals speichern (einschließlich passwords.js). Deine frühere Arbeit bleibt in ihrer eigenen Lektion. Lies die bereitgestellten Dateien, bevor du passwords.js bearbeitest. Diese Kopie enthält Hilfsfunktionen zum Hashen von Passwörtern und die bereitgestellten Debugging-Routen.
Bei der Registrierung werden jetzt gesalzene Hashes gespeichert. Füge einen Login hinzu, der ein Passwort mit dem vergleicht, was bei der Registrierung gespeichert wurde.
- Füge in
passwords.jseineasync-FunktionverifyPassword(password, stored)hinzu und exportiere sie.storedist ein bei der Registrierung gespeicherter Wert, zum Beispielf2bb...f065:c3f7...dbd2. Gibtruezurück, wennpassworddas Passwort ist, mit dem der Wert erstellt wurde, andernfallsfalse:- Nimm das Salt vor dem Doppelpunkt.
- Hashe
passwordmit diesem Salt zu einem 64-Byte-Schlüssel, genauso wiehashPassword. - Dekodiere den gespeicherten Schlüssel nach dem Doppelpunkt aus Hex. Wenn die beiden Schlüssel unterschiedlich lang sind, gib
falsezurück, ohnetimingSafeEqualaufzurufen, wie unter Schlüsselbytes vergleichen. Gib andernfalls das Vergleichsergebnis zurück.
- Importiere in
server.jsverifyPasswordnebenhashPassword. FügePOST /loginhinzu. Die Route erhält denselben Body wie die Registrierung, zum Beispiel{"username": "ada", "password": "correct horse"}.- Suche den Benutzer anhand dieses Benutzernamens.
verifyPasswordist langsam und gibt ein Promise zurück, also warte darauf. - Wenn der Benutzer existiert und das Passwort stimmt, antworte mit Status 200 und
{"username": "ada"}. - Antworte andernfalls mit Status 401 und
{"error": "Wrong username or password"}. 401 Unauthorized bedeutet, dass die Anfrage nicht nachgewiesen hat, wer sie stellt. - Sende bei einem falschen Passwort und bei einem Benutzernamen, mit dem sich niemand registriert hat, genau dieselbe 401-Antwort. So verrät der Antwort-Body niemandem, welche Benutzernamen existieren.
- Suche den Benutzer anhand dieses Benutzernamens.
Probiere es aus: Drücke „Spielen“. Sende POST /signup mit {"username": "ada", "password": "correct horse"}: Status 201. Sende POST /login mit demselben Body: Status 200 und {"username": "ada"}. Sende POST /login mit {"username": "ada", "password": "wrong horse"}: Status 401 und {"error": "Wrong username or password"}. Sende POST /login mit {"username": "nobody", "password": "correct horse"}: dieselbe 401-Antwort.
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.
export async function hashPassword(password) {
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(password, salt, 64);
return `${salt}:${key.toString('hex')}`;
}
Alle Lektionen in Authentifizierung und Sicherheit
Übe selbstständig: Express-Playground