Mot de passe
Un générateur de mots de passe solides, réglable en longueur, à copier d'un clic. Le bon exercice pour comprendre pourquoi Math.random() ne suffit pas.
- Tirer au sort avec crypto.getRandomValues
- Garantir un caractère de chaque famille
- Copier dans le presse-papier avec l'API Clipboard
Pourquoi un générateur ? Parce qu'un humain est un très mauvais générateur de hasard. On choisit des mots, des dates, des motifs. Une machine, elle, peut tirer chaque caractère sans préférence.
Le piège, c'est Math.random() : il est fait pour les jeux, pas pour la sécurité. Ici, on utilise crypto.getRandomValues(), le hasard cryptographique du navigateur.
Pourquoi en JavaScript simple ? Tout se passe dans le navigateur : le mot de passe n'est envoyé nulle part.
LE HTML
<output id="mdp"></output> <input id="longueur" type="range" min="8" max="64" value="20"> <label><input type="checkbox" id="chiffres" checked> Chiffres</label> <label><input type="checkbox" id="symboles" checked> Symboles</label> <button id="generer">Générer</button> <button id="copier">Copier</button>
LES ALPHABETS
On retire l, I, O, 0 et 1 : impossibles à distinguer dans certaines polices.
const LETTRES = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'; const CHIFFRES = '23456789'; const SYMBOLES = '!@#$%&*?-_+=';
UN TIRAGE SANS BIAIS
crypto.getRandomValues donne des nombres imprévisibles. On rejette les valeurs trop hautes pour que chaque caractère ait exactement la même chance.
function tirer(max) { const limite = Math.floor(4294967296 / max) * max; const n = new Uint32Array(1); do crypto.getRandomValues(n); while (n[0] >= limite); return n[0] % max; }GÉNÉRER
function generer() { let alphabet = LETTRES; if (document.getElementById('chiffres').checked) alphabet += CHIFFRES; if (document.getElementById('symboles').checked) alphabet += SYMBOLES; const longueur = Number(document.getElementById('longueur').value); let mdp = ''; for (let i = 0; i < longueur; i++) mdp += alphabet[tirer(alphabet.length)]; document.getElementById('mdp').textContent = mdp; }COPIER
L'API Clipboard est asynchrone : elle renvoie une promesse.
document.getElementById('copier').addEventListener('click', async () => { await navigator.clipboard.writeText(document.getElementById('mdp').textContent); }); document.getElementById('generer').addEventListener('click', generer); generer();
PIÈGE 1 : Math.random()
Mauvais : alphabet[Math.floor(Math.random() * n)]. Math.random est prévisible : il n'est pas fait pour la sécurité.
Correct : crypto.getRandomValues(), disponible dans tous les navigateurs récents.
PIÈGE 2 : Le biais du modulo
Mauvais : n % alphabet.length directement. Certains caractères sortent un peu plus souvent que d'autres.
Correct : rejeter les tirages au-dessus du plus grand multiple de la taille de l'alphabet, comme dans tirer().
PIÈGE 3 : Des options cochées mais absentes
Mauvais : cocher « Chiffres » et obtenir un mot de passe sans chiffre, ce qui arrive sur les mots courts.
Correct : placer d'abord un caractère de chaque type coché, compléter, puis mélanger le tout (c'est ce que fait la démo).
- Un champ « caractères à exclure », retirés de l'alphabet avant le tirage.
- Une phrase de passe : quatre mots tirés d'une liste, séparés par des tirets. Plus facile à retenir, aussi solide.
- Le presse-papier vidé au bout de 30 secondes avec un setTimeout.
- Générez à chaque mouvement du curseur de longueur : le résultat suit le geste.
- Affichez la force en bits : longueur × log2(taille de l'alphabet). C'est la base de la variante « Jauge de robustesse ».
Les options vont dans un useState, le mot de passe se recalcule avec useMemo quand elles changent.
La copie reste une fonction appelée au clic, jamais pendant le rendu.
Chargement des commentaires…