Menu
CoddyTech

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.

challenge icon

Aufgabe

Einfach

Dieser 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.

  1. Füge in passwords.js eine async-Funktion verifyPassword(password, stored) hinzu und exportiere sie. stored ist ein bei der Registrierung gespeicherter Wert, zum Beispiel f2bb...f065:c3f7...dbd2. Gib true zurück, wenn password das Passwort ist, mit dem der Wert erstellt wurde, andernfalls false:
    • Nimm das Salt vor dem Doppelpunkt.
    • Hashe password mit diesem Salt zu einem 64-Byte-Schlüssel, genauso wie hashPassword.
    • Dekodiere den gespeicherten Schlüssel nach dem Doppelpunkt aus Hex. Wenn die beiden Schlüssel unterschiedlich lang sind, gib false zurück, ohne timingSafeEqual aufzurufen, wie unter Schlüsselbytes vergleichen. Gib andernfalls das Vergleichsergebnis zurück.
  2. Importiere in server.js verifyPassword neben hashPassword. Füge POST /login hinzu. Die Route erhält denselben Body wie die Registrierung, zum Beispiel {"username": "ada", "password": "correct horse"}.
    • Suche den Benutzer anhand dieses Benutzernamens. verifyPassword ist 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.

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