Menu
CoddyTech

Non memorizzare mai le password

Fa parte della sezione Autenticazione e sicurezza del percorso Node.js di Coddy. Lezione 4 di 24.

Le persone riutilizzano le password, quindi una password in testo semplice trapelata può esporre gli account altrove. Memorizza l’hash salato di una password: un valore derivato che verifichi ricalcolandolo, anziché decodificarlo.

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

Questo esempio combina un salt e una chiave derivata per un codice d’invito. Il delimitatore permette alla verifica di recuperare il salt e derivare un’altra chiave con gli stessi parametri. L’esercizio sulle password usa un delimitatore e una lunghezza della chiave propri. Genera il salt per ogni nuova password, deriva la chiave e poi memorizza entrambi. Gli hash salati richiedono comunque password robuste, perché un aggressore può provare diverse ipotesi.

challenge icon

Sfida

Facile

Al momento la registrazione salva ogni password esattamente come è stata digitata. Fai in modo che salvi invece un hash con salt, così una fuga di dati dal database non riveli le password.

  1. In passwords.js, modifica hashPassword(password) in modo che restituisca il testo che la registrazione salva, nel formato salt, due punti, hash:
    • Il salt è composto da 16 byte casuali, generati da zero a ogni chiamata e scritti in esadecimale: 32 caratteri da 0 a 9 e da a a f.
    • L'hash è una chiave di 64 byte che scrypt crea a partire dalla password e dal salt, anch'essa scritta in esadecimale: 128 caratteri. Il terzo argomento di scryptAsync è la lunghezza della chiave in byte.
    • Unisci i due valori con due punti. Un valore salvato è simile a questo: f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
  2. Non devi modificare server.js. Il suo POST /signup chiama già hashPassword e salva ciò che restituisce. Include anche GET /debug/users/:username, che mostra ciò che è stato salvato per un utente. Questa route esiste solo per permetterti di controllare; una vera app non la include mai.

Prova: premi «Esegui». Invia POST /signup con {"username": "ada", "password": "correct horse"}. Riceverai lo stato 201 e {"username": "ada"}. Invia lo stesso corpo con "username": "bob". Ora invia GET /debug/users/ada, poi GET /debug/users/bob. Ogni passwordHash è composto da 32 caratteri, due punti e altri 128 caratteri. I due valori sono diversi, anche se ada e bob hanno scelto la stessa password.

Provalo tu

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

const scryptAsync = promisify(scrypt);

// Trasforma una password nel testo che signup memorizza.
// Per ora mantiene la password così come è stata digitata.
export async function hashPassword(password) {
    return password;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Autenticazione e sicurezza

Esercitati da solo: Playground Express