Menu
CoddyTech

Nigdy nie przechowuj haseł

Część sekcji Uwierzytelnianie i bezpieczeństwo ścieżki Node.js w Coddy. Lekcja 4 z 24.

Ludzie używają tych samych haseł w różnych miejscach, więc ujawnienie hasła w postaci jawnego tekstu może narazić na niebezpieczeństwo konta w innych serwisach. Zapisuj skrót hasła z solą: wartość pochodną, którą weryfikujesz przez ponowne jej obliczenie, zamiast ją dekodować.

const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');

Ten przykład łączy sól i klucz pochodny dla kodu zaproszenia. Separator pozwala podczas weryfikacji odzyskać sól i wyprowadzić kolejny klucz przy użyciu tych samych parametrów. W zadaniu dotyczącym haseł używasz własnego separatora i długości klucza. Generuj sól dla każdego nowego hasła, wyprowadzaj klucz, a następnie zapisuj oba. Skróty z solą nadal wymagają silnych haseł, ponieważ osoba atakująca może próbować odgadnąć hasło.

challenge icon

Wyzwanie

Łatwy

Obecnie rejestracja zapisuje każde hasło dokładnie w takiej postaci, w jakiej zostało wpisane. Zmień to tak, aby zamiast niego zapisywała skrót z solą, dzięki czemu wyciek bazy danych nie ujawni haseł.

  1. W pliku passwords.js zmień hashPassword(password) tak, aby zwracała tekst zapisywany przez rejestrację w postaci: sól, dwukropek, skrót:
    • Sól to 16 losowych bajtów, generowanych od nowa przy każdym wywołaniu i zapisanych w systemie szesnastkowym: 32 znaki od 0 do 9 oraz od a do f.
    • Skrót to klucz o długości 64 bajtów, który scrypt tworzy na podstawie hasła i soli; również jest zapisany w systemie szesnastkowym: 128 znaków. Trzeci argument funkcji scryptAsync określa długość klucza w bajtach.
    • Połącz je dwukropkiem. Zapisana wartość wygląda tak: f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
  2. Nie musisz zmieniać pliku server.js. Trasa POST /signup już wywołuje hashPassword i zapisuje zwróconą przez nią wartość. Dostępna jest też trasa GET /debug/users/:username, która pokazuje, co zapisano dla jednego użytkownika. Ta trasa istnieje tylko po to, żeby można było to sprawdzić; prawdziwa aplikacja nigdy jej nie ma.

Wypróbuj: Naciśnij „Uruchom”. Wyślij żądanie POST /signup z treścią {"username": "ada", "password": "correct horse"}. Otrzymasz status 201 i {"username": "ada"}. Wyślij tę samą treść, zmieniając nazwę użytkownika na "username": "bob". Następnie wyślij żądanie GET /debug/users/ada, a potem GET /debug/users/bob. Każda wartość passwordHash składa się z 32 znaków, dwukropka i kolejnych 128 znaków. Obie wartości są różne, mimo że ada i bob wybrali to samo hasło.

Spróbuj swoich sił

import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';

const scryptAsync = promisify(scrypt);

// Przekształca hasło w tekst przechowywany przez signup.
// Na razie zachowuje hasło w postaci wpisanej przez użytkownika.
export async function hashPassword(password) {
    return password;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Uwierzytelnianie i bezpieczeństwo

Poćwicz samodzielnie: Edytor online Express