Comment un entretien m'a poussé à créer Obscura — un générateur de mots de passe avec une vraie entropie
13 avril 2025 · 7 min read · Read in English
Sommaire
Introduction
Lors d'un entretien récent pour un poste d'ingénieur logiciel sécurité, j'ai reçu un défi : créer un générateur de mots de passe sécurisé qui prenne en compte la véritable entropie. L'interviewer voulait voir comment j'allais aborder le problème, et j'étais ravi de me lancer.
Au départ, je pensais que ce serait simple. J'avais déjà utilisé des générateurs de mots de passe
(à base de Math.random et compagnie), et je supposais qu'il serait facile d'en créer un sûr.
Mais la conversation s'est rapidement éloignée des implémentations superficielles pour aller vers
un sujet plus profond et souvent négligé : l'entropie — et la façon dont la plupart des
prétendus générateurs ne la traitent pas correctement.
Le défi
L'interviewer insistait sur le fait que l'entropie devait être mesurable, ajustable, et prévisible selon les choix de l'utilisateur. Il ne cherchait pas un simple outil qui balance des caractères aléatoires ; il voulait un générateur capable de :
- quantifier l'entropie de l'information du mot de passe généré,
- s'adapter aux contraintes du pool de caractères (exclure les doublons ou les caractères spéciaux),
- éviter les motifs et séquences communs (par ex. « 123 », « qwerty » ou « abc »),
- et tout en restant simple d'usage et robuste face aux attaques par force brute.
Ça m'a fait réfléchir au fait que la majorité des générateurs de mots de passe ne sont, au fond, que des générateurs de caractères aléatoires un peu glorifiés.
Mon raisonnement : comprendre l'entropie
J'ai commencé par lui demander la définition de l'entropie dans le contexte de la génération de mots de passe. Il m'a expliqué que l'entropie est une mesure de l'incertitude ou du caractère aléatoire d'un système. Pour les mots de passe, elle désigne le degré d'imprévisibilité du mot de passe lui-même. Plus un mot de passe est imprévisible, plus son entropie est élevée, et plus il est résistant aux attaques par force brute. (Je me suis dit : allez mec, t'étais censé me faire comprendre le concept, pas le compliquer 🙁 — parce que je ne savais ni le mesurer, ni le calculer.)
Après quelques minutes de discussion, il m'a donné la formule de l'entropie, simple mais puissante :
E = log2(P^L)
Où :
- E est l'entropie en bits
- P est la taille du pool de caractères (par ex. 26 pour les minuscules, 10 pour les chiffres, etc.)
- L est la longueur du mot de passe
Et voici l'exemple de calcul qu'il m'a donné. Pour un mot de passe utilisant 26 lettres minuscules et une longueur de 8 :
E = log2(26^8) = 8 * log2(26) ≈ 37.6 bits
Un mot de passe fort doit avoir au moins 80 bits d'entropie, donc je devais m'assurer que mon générateur augmente l'entropie en utilisant :
- Un pool de caractères plus large (majuscules, minuscules, chiffres, caractères spéciaux)
- Une longueur de mot de passe plus importante
- Un vrai aléa pour la sélection des caractères (pas du pseudo-aléa)
Après tous ces détails, j'ai compris deux choses :
- Plus le pool est grand et plus le mot de passe est long, plus il est solide.
- L'entropie se mesure en bits, et plus de bits signifie plus de combinaisons possibles.
Mais si on exclut les caractères similaires, qu'on impose l'unicité ou qu'on commence par un caractère spécifique, le pool rétrécit — et l'entropie diminue. Il faut donc calculer l'entropie dynamiquement en fonction des choix actuels de l'utilisateur.
La solution : construire un vrai générateur de mots de passe
J'ai écrit la première version du générateur en TypeScript, en me concentrant uniquement sur la logique. Il propose des options comme :
- inclure/exclure majuscules, minuscules, chiffres, caractères spéciaux
- exclure les caractères similaires (par ex. « l » et « 1 », « O » et « 0 »)
- éviter les doublons et les motifs séquentiels
- générer plusieurs mots de passe à la fois
- et surtout : le calcul d'entropie en temps réel
Approche de conception
Mon implémentation suit une approche modulaire autour de la fonction centrale generatePassword.
J'ai défini une interface PasswordOptions claire pour rendre le code plus lisible et fortement
typé.
export interface PasswordOptions {
length: number
includeLowercase: boolean
includeUppercase: boolean
includeDigits: boolean
includeSymbols: boolean
excludeSimilarCharacters: boolean
noDuplicateCharacters: boolean
noSequentialCharacters: boolean
beginWithLetter: boolean
quantity: number
}
Construction du pool de caractères
Le socle du code est la sélection du pool de caractères. J'ai défini des constantes par jeu de caractères et écrit une fonction utilitaire pour construire un pool personnalisé selon les préférences de l'utilisateur :
function getCharacterPool(options: PasswordOptions): string {
let pool = ''
if (options.includeLowercase) pool += LOWERCASE
if (options.includeUppercase) pool += UPPERCASE
if (options.includeDigits) pool += DIGITS
if (options.includeSymbols) pool += SYMBOLS
if (options.excludeSimilarCharacters) {
pool = pool
.split('')
.filter((c) => !SIMILAR.includes(c))
.join('')
}
return pool
}
Cette approche offre un contrôle fin sur le jeu de caractères, ce qui impacte directement le calcul de l'entropie.
Considérations de sécurité
J'ai implémenté plusieurs mécanismes pour garantir des mots de passe robustes :
- Aléa cryptographiquement sûr : au lieu de
Math.random(), j'ai utilisé l'API Web Cryptocrypto.getRandomValues()pour un vrai aléa :function getRandomChar(pool: string): string { const randomIndex = crypto.getRandomValues(new Uint32Array(1))[0] % pool.length return pool.charAt(randomIndex) } - Détection des motifs séquentiels : pour éviter les motifs faibles comme « abc » ou « 123 »,
j'ai ajouté une fonction qui détecte les séquences :
function hasSequentialCharacters(password: string): boolean { for (let i = 0; i < password.length - 2; i++) { const a = password.charCodeAt(i) const b = password.charCodeAt(i + 1) const c = password.charCodeAt(i + 2) if ((b === a + 1 && c === b + 1) || (b === a - 1 && c === b - 1)) { return true } } return false } - Validation des entrées : le code interdit les combinaisons impossibles, comme exiger l'unicité des caractères pour un mot de passe plus long que le pool disponible.
Logique de génération
L'algorithme principal utilise un mécanisme de réessai pour garantir le respect de toutes les contraintes :
- générer le premier caractère (éventuellement une lettre)
- construire le reste du mot de passe caractère par caractère
- valider chaque contrainte (unicité, motifs séquentiels, etc.)
- si une contrainte échoue, recommencer toute la génération
Cette approche assure que chaque mot de passe généré satisfait toutes les exigences de sécurité.
Sortie finale
La fonction generatePassword orchestre l'ensemble, en imposant des limites raisonnables
(8 à 64 caractères) et en générant la quantité de mots de passe demandée :
export function generatePasswords(options: PasswordOptions): string[] {
const safeLength = Math.max(8, Math.min(options.length, 64))
const passwords: string[] = []
for (let i = 0; i < options.quantity; i++) {
passwords.push(generatePassword({ ...options, length: safeLength }))
}
return passwords
}
Cette implémentation équilibre sécurité, ergonomie et performance, ce qui en fait un générateur de mots de passe robuste pour des cas réels.
Pourquoi c'est important
J'ai beaucoup appris de ce défi d'entretien, et j'ai réalisé que la plupart des générateurs de mots de passe sont juste des générateurs de caractères aléatoires un peu glorifiés. Ils ne prennent pas en compte l'entropie réelle. Une bonne hygiène des mots de passe est cruciale — et nous avons tous réutilisé un mot de passe au moins une fois. Des outils comme Obscura donnent à l'utilisateur confiance et contrôle sans compromis sur la vie privée.
Quelques conseils pour une meilleure sécurité :
- utilisez toujours un mot de passe unique pour chaque compte
- privilégiez les mots de passe longs (16+ caractères)
- évitez les motifs prévisibles ou les informations personnelles (anniversaires, prénoms, etc.)
- utilisez un gestionnaire de mots de passe (Obscura est parfait pour générer des mots de passe forts à y stocker)
- ne partagez jamais, au grand jamais, vos mots de passe
Mon expérience du process
Malheureusement, mon parcours avec l'entreprise ne s'est pas étendu au-delà de l'entretien technique. D'après leurs retours, ils cherchent quelqu'un avec une expérience plus poussée en ingénierie logicielle et des certifications sécurité formelles comme CISSP, CLSSP, COMPTIA Security+, etc.
Mon profil est principalement orienté ingénierie logicielle dans les systèmes distribués, avec un focus sur Kubernetes et les pratiques DevSecOps. J'ai de l'expérience sur les aspects sécurité comme l'analyse SAST/DAST, le scan de vulnérabilités des dépendances, la sécurité des conteneurs, les revues de sécurité IaC et la gestion IAM / des secrets — mais ils cherchaient un profil plus spécialisé en sécurité.
Malgré le résultat, j'ai vraiment apprécié le process d'entretien et j'ai beaucoup appris du challenge. J'ai décidé d'en tirer quelque chose d'utile, et c'est comme ça qu'Obscura est né.
Essaie-le, forke-le, partage-le, contribue
Tu peux essayer Obscura sur obscura.denisakp.me et consulter le code sur GitHub. Tes retours, suggestions ou contributions sont les bienvenus. Le projet est open source : toute amélioration ou nouvelle fonctionnalité que tu voudrais ajouter est appréciée.
S'abonner aux prochains articles
Recevez les nouveaux articles par e-mail. Pas de spam, désinscription à tout moment.