Motifs1 chasse jouable incluse

Règles de mot de passe avec des lookaheads en regex (et quand s'en passer)

Comment vérifier « au moins une majuscule, un chiffre, huit caractères » en une seule regex grâce aux lookaheads, pourquoi la version sans ordre imposé en a besoin, les pièges des motifs courants, et pourquoi vérifier chaque règle séparément est souvent la meilleure conception.

Logo de Regex Hunter

· 6 min de lecture

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

à attraper

  • Secret123
  • aB3defgh
  • Tr0ub4dor
  • 9Lives_cat

à épargner

  • secret123
  • SECRET123
  • Secretpass
  • Ab1

« Au moins 8 caractères, avec une majuscule, une minuscule et un chiffre. » C'est l'une des demandes les plus fréquentes qu'on fait à une regex, et c'est un bon moyen d'apprendre les lookaheads (assertions avant), parce que les règles ne disent pas où se trouve chaque caractère.

Cet article construit le motif règle par règle, passe en revue les pièges, et se termine par un plaidoyer pour ne pas utiliser une seule grosse regex. Chaque exemple est interactif : modifiez les motifs et regardez les lignes changer.

Réponse rapideJavaScript
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

Au moins 8 caractères, dont au moins une minuscule, une majuscule et un chiffre, dans n'importe quel ordre.

Accepte

  • Secret123
  • 9Lives_cat
  • aB3defgh

Rejette

  • secret123
  • SECRET123
  • Ab1

01Pourquoi un motif simple n'y arrive pas

Un motif se lit de gauche à droite. Pour dire « contient un chiffre », vous écririez quelque chose comme .*\d.*, et ça va très bien tout seul. Mais « contient un chiffre et une majuscule », dans n'importe quel ordre, oblige à énumérer tous les ordres :

Motif31 car.
/^(.*[A-Z].*\d.*|.*\d.*[A-Z].*)$/
Essayez-le dans le bac à sable
Deux règles, deux ordres. Trois règles demanderaient six branches, quatre règles vingt-quatre.

Ça devient vite ingérable. Il faut un moyen de vérifier une règle sans avancer dans le texte.

02Les lookaheads vérifient sans avancer

Un lookahead (?=…) vérifie que quelque chose correspond à partir de la position actuelle, puis revient à son point de départ. Plusieurs lookaheads placés au début peuvent donc chacun parcourir tout le mot de passe, une règle chacun.

Une règle : « quelque part plus loin, il y a un chiffre » :

Correspondances3/3 comme prévu
/^(?=.*\d)/

Doit correspondre2/2

  • abc1
  • 1abc

Ne doit pas1/1

  • abcd
Essayez-le dans le bac à sable
(?=.*\d) cherche plus loin « n'importe quoi, puis un chiffre ». S'il le trouve, la correspondance réussit à la position 0.

C'est le .* avant \d qui permet le « quelque part ». Sans lui, (?=\d) voudrait dire « le tout prochain caractère est un chiffre ».

03Empiler les règles

Chaque règle a son propre lookahead, tous ancrés au début, puis la vérification de longueur consomme le texte :

Correspondances7/7 comme prévu
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

Doit correspondre3/3

  • Secret123
  • aB3defgh
  • 9Lives_cat

Ne doit pas4/4

  • secret123
  • SECRET123
  • Secretpass
  • Ab1
Essayez-le dans le bac à sable
Trois lookaheads (une minuscule, une majuscule, un chiffre), puis 8 caractères ou plus, quels qu'ils soient.

Lisez-le comme une liste de conditions. Ajouter une règle, c'est ajouter un lookahead, dans n'importe quel ordre :

Correspondances3/3 comme prévu
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9]).{8,}$/

Doit correspondre2/2

  • Secret123!
  • p@ssW0rd

Ne doit pas1/1

  • Secret123
Essayez-le dans le bac à sable
Un quatrième lookahead exige un symbole : tout caractère qui n'est ni une lettre ni un chiffre.

Un lookahead qui interdit quelque chose s'écrit (?!…). « Aucune espace nulle part » :

Correspondances2/2 comme prévu
/^(?!.*\s)(?=.*\d).{8,}$/

Doit correspondre1/1

  • correct1horse

Ne doit pas1/1

  • correct 1 horse
Essayez-le dans le bac à sable
(?!.*\s) échoue si un caractère d'espacement apparaît n'importe où plus loin.

04Les pièges des motifs courants

Oublier les ancres. Sans ^ et $, .{8,} n'a besoin que de huit caractères quelque part, et chaque lookahead part de l'endroit où la correspondance commence par hasard. Gardez ^ en tête pour que tous les lookaheads partent de la position 0, et $ à la fin pour que la vérification de longueur couvre toute la chaîne.

Une longueur maximale qui ne marche pas. .{8,64} sans $ trouve sans broncher les 64 premiers caractères d'un mot de passe de 500 caractères. Avec $, il le rejette, ce qui est bien ce que vous vouliez.

Un « symbole » trop restrictif. Une classe comme [!@#$%^&*] rejette ?, ~, -, les espaces et tout caractère hors de l'alphabet anglais. [^A-Za-z0-9] (« ni une lettre ni un chiffre ») correspond généralement à ce qu'on veut dire.

Les lettres hors de A à Z. [A-Z] ne compte pas É comme une majuscule. Avec le marqueur u, \p{Lu} et \p{Ll} désignent n'importe quelle lettre majuscule ou minuscule.

05Quand s'en passer

Une regex donne une seule réponse : oui ou non. Votre formulaire d'inscription doit dire à la personne quelle règle elle n'a pas respectée :

const rules = [
  { test: (p) => p.length >= 12, message: "Use at least 12 characters" },
  { test: (p) => /\d/.test(p),   message: "Add a number" },
  { test: (p) => /[A-Z]/.test(p), message: "Add a capital letter" },
];

const problems = rules.filter((r) => !r.test(password)).map((r) => r.message);

Chaque vérification est minuscule, lisible et facile à modifier, et les messages d'erreur viennent tout seuls.

Il vaut aussi la peine de se demander si vous voulez vraiment des règles de composition. Les recommandations du NIST sur les mots de passe (SP 800-63B) déconseillent les règles du type « une majuscule, un chiffre, un symbole ». Elles poussent les gens vers Password1!. Ces recommandations privilégient la longueur, en autorisant de longues phrases de passe (au moins 64 caractères, espaces compris), et la vérification des nouveaux mots de passe contre des listes de mots de passe déjà divulgués.

Le motif à lookaheads vaut donc la peine d'être connu, pour les mots de passe comme pour toute vérification du type « doit contenir tous ces éléments, dans n'importe quel ordre ». Pour un vrai formulaire d'inscription, une longueur minimale plus une vérification des mots de passe divulgués fait généralement mieux.

06À vous de jouer

Attrapez les chaînes qui contiennent à la fois un chiffre et une lettre, dans n'importe quel ordre :

Chasse jouablepar 20

Attrapez les chaînes qui ont au moins une lettre et au moins un chiffre, dans n'importe quel ordre.

Cibles · 0/6 attrapées

  • a1cible
  • 1acible
  • abc123cible
  • 123abccible
  • x9ycible
  • R2D2cible

Innocents · erreurs : 0

  • abcinnocent
  • 123innocent
  • ---innocent
  • a-binnocent
  • 4-5innocent
  • !!innocent

Tapez une regex — le plateau se met à jour en direct.

Essayez-le dans le bac à sable
Ça vous plaît ? Une nouvelle chasse chaque jour.Jouer la chasse du jour

07Récapitulatif

  • (?=.*X) signifie « X apparaît quelque part plus loin ». Empilez-en un par règle.
  • (?!.*X) signifie « X n'apparaît nulle part plus loin ».
  • Ancrez avec ^ pour que chaque lookahead parte de la position 0, et avec $ pour qu'une limite de longueur couvre tout.
  • [^A-Za-z0-9] fait un meilleur « symbole » qu'une liste choisie à la main.
  • Pour les formulaires, des vérifications séparées donnent des messages d'erreur séparés.
  • La longueur et une vérification des mots de passe divulgués valent mieux que des règles de composition.

08Continuez à vous entraîner