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.
Sfida
FacileAl 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.
- In
passwords.js, modificahashPassword(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
scryptcrea a partire dalla password e dal salt, anch'essa scritta in esadecimale: 128 caratteri. Il terzo argomento discryptAsyncè la lunghezza della chiave in byte. - Unisci i due valori con due punti. Un valore salvato è simile a questo:
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- Non devi modificare
server.js. Il suoPOST /signupchiama giàhashPassworde salva ciò che restituisce. Include ancheGET /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;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Autenticazione e sicurezza
1Password
Byte e testo esadecimaleDerivare una chiave dalla passwordUn nuovo saltNon memorizzare mai le passwordConfrontare i byte della chiaveVerificare una passwordRegole di registrazioneEsercitati da solo: Playground Express