Menu
CoddyTech

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.

challenge icon

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.

  1. Dans passwords.js, modifiez hashPassword(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 scrypt crée à partir du mot de passe et de ce sel, elle aussi écrite en hexadécimal : 128 caractères. Le troisième argument de scryptAsync correspond à la longueur de la clé en octets.
    • Réunissez les deux avec un deux-points. Une valeur enregistrée ressemble à ceci : f2bba0669d9fa2d203afc7e61bf8f065:c3f7cae352e023a8d4766da9a316b5a2c844100efff22c4079f89a8ab8512ac91c33227481c3afa88c3ba0e88347f9e3e0c22dad9d55f19688a350f71be8dbd2
  2. Vous n’avez pas besoin de modifier server.js. Son POST /signup appelle déjà hashPassword et enregistre la valeur renvoyée. Il contient aussi GET /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;
}
quiz iconTestez-vous

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é

Entraînez-vous par vous-même : Playground Express