Ne stockez jamais les mots de passe
Fait partie de la section Authentification et sécurité du Journey Node.js de Coddy. Leçon 4 sur 24.
Les gens réutilisent leurs mots de passe, donc la fuite d’un mot de passe en clair peut exposer des comptes ailleurs. Stocke une empreinte de mot de passe salée : une valeur dérivée que tu vérifies en la recalculant, plutôt qu’en la décodant.
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync(inviteCode, salt, 32);
const saved = salt + '.' + key.toString('hex');Cet exemple associe un sel et une clé dérivée pour un code d’invitation. Le séparateur permet à la vérification de récupérer le sel et de dériver une autre clé avec les mêmes paramètres. Ton exercice sur les mots de passe utilise son propre séparateur et sa propre longueur de clé. Génère un sel pour chaque nouveau mot de passe, dérive la clé, puis stocke les deux. Les empreintes salées nécessitent tout de même des mots de passe robustes, car un attaquant peut essayer des mots de passe au hasard.
Défi
FacileÀ présent, l’inscription enregistre chaque mot de passe exactement comme il a été saisi. Faites-lui plutôt enregistrer un hachage salé, afin qu’une fuite de la base de données ne révèle pas les mots de passe.
- Dans
passwords.js, modifiezhashPassword(password)pour qu’elle renvoie le texte enregistré lors de l’inscription, sous la forme sel, deux-points, hachage :- Le sel est constitué de 16 octets aléatoires, générés à chaque appel et écrits en hexadécimal : 32 caractères de 0 à 9 et de a à f.
- Le hachage est une clé de 64 octets que
scryptcrée à partir du mot de passe et de ce sel, elle aussi écrite en hexadécimal : 128 caractères. Le troisième argument descryptAsynccorrespond à la longueur de la clé en octets. - Réunissez les deux avec un deux-points. Une valeur enregistrée ressemble à ceci :
f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
- Vous n’avez pas besoin de modifier
server.js. SonPOST /signupappelle déjàhashPasswordet enregistre la valeur renvoyée. Il contient aussiGET /debug/users/:username, qui affiche ce qui a été enregistré pour un utilisateur. Cette route existe uniquement pour que vous puissiez regarder ; une vraie application ne la possède jamais.
Essayez : Appuyez sur « Jouer ». Envoyez POST /signup avec {"username": "ada", "password": "correct horse"}. Vous obtenez le statut 201 et {"username": "ada"}. Envoyez le même corps avec "username": "bob". Envoyez ensuite GET /debug/users/ada, puis GET /debug/users/bob. Chaque passwordHash comporte 32 caractères, un deux-points, puis 128 autres caractères. Les deux valeurs sont différentes, même si ada et bob ont choisi le même mot de passe.
Essayez vous-même
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// Transforme un mot de passe en texte stocké par signup.
// Pour l’instant, il conserve le mot de passe tel qu’il a été saisi.
export async function hashPassword(password) {
return password;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Authentification et sécurité
1Mots de passe
Octets et texte hexadécimalDériver une clé de mot de passeUn nouveau selNe stockez jamais les mots de passeComparer les octets de cléVérifier un mot de passeRègles d’inscriptionEntraînez-vous par vous-même : Playground Express