Regex pour valider la force du mot de passe

142

Mes critères de force de mot de passe sont les suivants:

  • Longueur de 8 caractères
  • 2 lettres en majuscules
  • 1 caractère spécial (!@#$&*)
  • 2 chiffres (0-9)
  • 3 lettres en minuscules

Quelqu'un peut-il me donner une expression régulière pour la même chose. Toutes les conditions doivent être remplies par mot de passe.

Ajay Kelkar
la source
2
Êtes-vous vraiment prêt à confier vos mesures de sécurité par mot de passe à Internet en général?
Borealid
12
@Borealid: la publication de vos politiques de mot de passe ne devrait généralement pas avoir un impact significatif sur votre sécurité. Si c'est le cas, alors vos politiques sont mauvaises ("Seulement passwordet hello123sont des mots de passe valides!").
Joachim Sauer
3
@Joachim Sauer: Ce n'est pas ce que je voulais dire. Ce que je voulais dire, c'est que l'affiche va probablement faire confiance à toute expression régulière qu'il reçoit. Pas une si bonne idée.
Borealid
3
En fait, cette expression régulière sera dans le code de service, je vais tester les cas de différence, ne pas y croire aveuglément :)
Ajay Kelkar
9
Les règles de mot de passe complexes ne conduiront généralement pas à des mots de passe plus sûrs, il est important qu'une longueur minimale soit limitée. Les gens ne peuvent pas se souvenir de tonnes de mots de passe forts, et ces règles peuvent interférer avec les bons schémas de mots de passe. Les gens peuvent devenir très inventifs pour contourner ces règles, par exemple en utilisant des mots de passe faibles comme "Password-2014". Vous vous retrouvez souvent avec des mots de passe plus faibles au lieu de mots plus forts.
martinstoeckli

Réponses:

428

Vous pouvez effectuer ces vérifications à l'aide d'assertions d'anticipation positives:

^(?=.*[A-Z].*[A-Z])(?=.*[!@#$&*])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z].*[a-z]).{8}$

Lien rubulaire

Explication:

^                         Start anchor
(?=.*[A-Z].*[A-Z])        Ensure string has two uppercase letters.
(?=.*[!@#$&*])            Ensure string has one special case letter.
(?=.*[0-9].*[0-9])        Ensure string has two digits.
(?=.*[a-z].*[a-z].*[a-z]) Ensure string has three lowercase letters.
.{8}                      Ensure string is of length 8.
$                         End anchor.
codaddict
la source
92
Pour tous ceux qui veulent une durée d'au moins n, remplacez-le .{8}par.{n,}
NullUserException
14
+1 pour une explication complète. Mes règles de mot de passe sont différentes mais en fonction de votre réponse, je peux adapter l'expression régulière.
Morvael
14
Merci d'avoir décrit ce qui se passe dans l'expression régulière. Cela constitue un excellent exemple d'apprentissage pour ceux d'entre nous qui n'ont jamais vraiment compris la syntaxe.
4
J'apprécie également l'explication de l'expression régulière. Trop souvent, j'utilise des regex complexes que j'ai trouvées, sans vraiment comprendre ce qui se passe.
Nicholas Smith
4
Grand modèle, je me demande pourquoi ne pas utiliser de quantificateurs? Au moins 1 spécial, 1 chiffre, 1 caractère spécial, 8 caractères: ^ (? =. * ([AZ]) {1,}) (? =. * [! @ # $ & *] {1,}) ( ? =. * [0-9] {1,}) (? =. * [Az] {1,}). {8,100} $
RockOnGom
11

Vous pouvez utiliser des anticipations positives de longueur nulle pour spécifier chacune de vos contraintes séparément:

(?=.{8,})(?=.*\p{Lu}.*\p{Lu})(?=.*[!@#$&*])(?=.*[0-9])(?=.*\p{Ll}.*\p{Ll})

Si votre moteur regex ne prend pas en charge la \pnotation et que l'ASCII pur suffit, vous pouvez remplacer \p{Lu}par [A-Z]et \p{Ll}par [a-z].

Joachim Sauer
la source
8

Les réponses données ci-dessus sont parfaites, mais je suggère d'utiliser plusieurs expressions régulières plus petites plutôt qu'une grande.
Le fractionnement de l'expression régulière longue présente certains avantages:

  • facilité d'écriture et de lecture
  • facilité de débogage
  • facilité pour ajouter / supprimer une partie de regex

En général, cette approche permet de maintenir le code facilement .

Cela dit, je partage un morceau de code que j'écris en Swift à titre d'exemple:

struct RegExp {

    /**
     Check password complexity

     - parameter password:         password to test
     - parameter length:           password min length
     - parameter patternsToEscape: patterns that password must not contains
     - parameter caseSensitivty:   specify if password must conforms case sensitivity or not
     - parameter numericDigits:    specify if password must conforms contains numeric digits or not

     - returns: boolean that describes if password is valid or not
     */
    static func checkPasswordComplexity(password password: String, length: Int, patternsToEscape: [String], caseSensitivty: Bool, numericDigits: Bool) -> Bool {
        if (password.length < length) {
            return false
        }
        if caseSensitivty {
            let hasUpperCase = RegExp.matchesForRegexInText("[A-Z]", text: password).count > 0
            if !hasUpperCase {
                return false
            }
            let hasLowerCase = RegExp.matchesForRegexInText("[a-z]", text: password).count > 0
            if !hasLowerCase {
                return false
            }
        }
        if numericDigits {
            let hasNumbers = RegExp.matchesForRegexInText("\\d", text: password).count > 0
            if !hasNumbers {
                return false
            }
        }
        if patternsToEscape.count > 0 {
            let passwordLowerCase = password.lowercaseString
            for pattern in patternsToEscape {
                let hasMatchesWithPattern = RegExp.matchesForRegexInText(pattern, text: passwordLowerCase).count > 0
                if hasMatchesWithPattern {
                    return false
                }
            }
        }
        return true
    }

    static func matchesForRegexInText(regex: String, text: String) -> [String] {
        do {
            let regex = try NSRegularExpression(pattern: regex, options: [])
            let nsString = text as NSString
            let results = regex.matchesInString(text,
                options: [], range: NSMakeRange(0, nsString.length))
            return results.map { nsString.substringWithRange($0.range)}
        } catch let error as NSError {
            print("invalid regex: \(error.localizedDescription)")
            return []
        }
    }
}
Luca Davanzo
la source
De plus, en utilisant des expressions régulières complexes comme ci-dessus, il est très facile de s'ouvrir à un retour en arrière catastrophique ( regular-expressions.info/catastrophic.html ). Cela peut passer inaperçu jusqu'au jour où votre serveur se bloque avec 100% de CPU parce qu'un utilisateur a utilisé un mot de passe "étrange". Exemple: ^ ([a-z0-9] +) {8,} $ (pouvez-vous voir l'erreur?)
aKzenT
5

Je suggérerais d'ajouter

(?!.*pass|.*word|.*1234|.*qwer|.*asdf) exclude common passwords
Stuart
la source
1

La solution de codaddict fonctionne bien, mais celle-ci est un peu plus efficace: (syntaxe Python)

password = re.compile(r"""(?#!py password Rev:20160831_2100)
    # Validate password: 2 upper, 1 special, 2 digit, 1 lower, 8 chars.
    ^                        # Anchor to start of string.
    (?=(?:[^A-Z]*[A-Z]){2})  # At least two uppercase.
    (?=[^!@#$&*]*[!@#$&*])   # At least one "special".
    (?=(?:[^0-9]*[0-9]){2})  # At least two digit.
    .{8,}                    # Password length is 8 or more.
    $                        # Anchor to end of string.
    """, re.VERBOSE)

Les classes de caractères annulées consomment tout jusqu'au caractère souhaité en une seule étape, ne nécessitant aucun retour arrière. (La solution dot star fonctionne très bien, mais nécessite un certain retour en arrière.) Bien sûr, avec des chaînes cibles courtes telles que des mots de passe, cette amélioration de l'efficacité sera négligeable.

ridgerunner
la source
Pourriez-vous s'il vous plaît vérifier si c'est correct? Je suis dans le doute à cause de l'ouverture du crochet rond en première ligne entre le triple guillemet double et le point d'interrogation. Je peux voir que le commentaire Python (hachage) est plus tard. Je ne vois pas le correspondant fermant le crochet rond près de l'ancre d'extrémité (signe dollar). Devrait mentionner que je ne suis pas un profy regex.
lospejos
@lospejos - Le # n'est pas le début d'un commentaire régulier d'une ligne. Ce hachage fait partie d'un groupe de commentaires qui commence par a (?#et se termine par a ). Il n'y a pas de parens déséquilibrés dans cette expression régulière.
ridgerunner
1
import re

RegexLength=re.compile(r'^\S{8,}$')
RegexDigit=re.compile(r'\d')
RegexLower=re.compile(r'[a-z]')
RegexUpper=re.compile(r'[A-Z]')


def IsStrongPW(password):
    if RegexLength.search(password) == None or RegexDigit.search(password) == None or RegexUpper.search(password) == None or RegexLower.search(password) == None:
        return False
    else:
        return True

while True:
    userpw=input("please input your passord to check: \n")
    if userpw == "exit":
        break
    else:
        print(IsStrongPW(userpw))
lierre qin
la source
1

La solution de @ codaddict fonctionnera.

Vous devriez également envisager de modifier certaines de vos règles pour:

  1. Ajoutez plus de caractères spéciaux, c'est-à-dire%, ^, (,), -, _, + et point. J'ajoute tous les caractères spéciaux que vous avez manqués au-dessus des signes numériques dans les claviers américains. Échappez à ceux que les regex utilisent.
  2. Faites le mot de passe de 8 caractères ou plus. Pas seulement un nombre statique 8.

Avec les améliorations ci-dessus, et pour plus de flexibilité et de lisibilité, je modifierais l'expression régulière en.

^(?=.*[a-z]){3,}(?=.*[A-Z]){2,}(?=.*[0-9]){2,}(?=.*[!@#$%^&*()--__+.]){1,}.{8,}$

Explication de base

(?=.*RULE){MIN_OCCURANCES,}     Each rule block is shown by (){}. The rule and number of occurrences can then be easily specified and tested separately, before getting combined

Explication détaillée

^                             start anchor
(?=.*[a-z]){3,}               lowercase letters. {3,} indicates that you want 3 of this group
(?=.*[A-Z]){2,}               uppercase letters. {2,} indicates that you want 2 of this group
(?=.*[0-9]){2,}               numbers. {2,} indicates that you want 2 of this group
(?=.*[!@#$%^&*()--__+.]){1,}   all the special characters in the [] fields. The ones used by regex are escaped by using the \ or the character itself. {1,} is redundant, but good practice, in case you change that to more than 1 in the future. Also keeps all the groups consistent
{8,}                          indicates that you want 8 or more
$                             end anchor

Et enfin, à des fins de test, voici un robulink avec le regex ci-dessus

lsu_guy
la source
Merci @AFract. Je l'utilise dans mon code. J'aime la lisibilité et la répétabilité, lorsque vous devez revenir en arrière et le modifier à l'avenir, c'est-à-dire en cas de changement de politique de mot de passe :)
lsu_guy
0

Pour PHP, cela fonctionne très bien!

 if(preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 
 'CaSu4Li8')){
    return true;
 }else{
    return fasle;
 }

dans ce cas le résultat est vrai

Thsks pour @ridgerunner

Alejandro Peña
la source
pourquoi pas return preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 'CaSu4Li8')?
aloisdg passe à codidact.com
0

Une autre solution:

import re

passwordRegex = re.compile(r'''(
    ^(?=.*[A-Z].*[A-Z])                # at least two capital letters
    (?=.*[!@#$&*])                     # at least one of these special c-er
    (?=.*[0-9].*[0-9])                 # at least two numeric digits
    (?=.*[a-z].*[a-z].*[a-z])          # at least three lower case letters
    .{8,}                              # at least 8 total digits
    $
    )''', re.VERBOSE)

def userInputPasswordCheck():
    print('Enter a potential password:')
    while True:
        m = input()
        mo = passwordRegex.search(m) 
        if (not mo):
           print('''
Your password should have at least one special charachter,
two digits, two uppercase and three lowercase charachter. Length: 8+ ch-ers.

Enter another password:''')          
        else:
           print('Password is strong')
           return
userInputPasswordCheck()
S.Sergey
la source
0

Le mot de passe doit respecter au moins 3 des 4 règles de complexité suivantes,

[au moins 1 caractère majuscule (AZ) au moins 1 caractère minuscule (az) au moins 1 chiffre (0-9) au moins 1 caractère spécial - n'oubliez pas de traiter également l'espace comme des caractères spéciaux]

au moins 10 caractères

au plus 128 caractères

pas plus de 2 caractères identiques dans une ligne (par exemple, 111 non autorisés)

'^ (?!. (.) \ 1 {2}) ((? =. [Az]) (? =. [AZ]) (? =. [0-9]) | (? =. [Az] ) (? =. [AZ]) (? =. [^ A-zA-Z0-9]) | (? =. [AZ]) (? =. [0-9]) (? =. [^ A -zA-Z0-9]) | (? =. [az]) (? =. [0-9]) (? =. * [^ a-zA-Z0-9])). {10,127} $ '

(?!. * (.) \ 1 {2})

(? =. [az]) (? =. [AZ]) (? =. * [0-9])

(? =. [az]) (? =. [AZ]) (? =. * [^ a-zA-Z0-9])

(? =. [AZ]) (? =. [0-9]) (? =. * [^ A-zA-Z0-9])

(? =. [az]) (? =. [0-9]) (? =. * [^ a-zA-Z0-9])

. {10.127}

Ra Vi
la source
0

Toutes les expressions régulières ci-dessus n'ont malheureusement pas fonctionné pour moi. Les règles de base d'un mot de passe fort sont

  • Doit contenir au moins une majuscule
  • Doit contenir au moins une petite lettre
  • Doit contenir au moins un nombre
  • Doit contenir au moins un caractère spécial
  • Et longueur minimale

Donc, Best Regex serait

^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*]).{8,}$

L'expression régulière ci-dessus a une longueur minimale de 8. Vous pouvez la changer de {8,} à { any_number ,}

Modification des règles?

disons que vous voulez un minimum de x caractères minuscules, y caractères majuscules, z caractères chiffres, longueur minimale totale w . Ensuite, essayez ci-dessous regex

^(?=.*[a-z]{x,})(?=.*[A-Z]{y,})(?=.*[0-9]{z,})(?=.*[!@#\$%\^&\*]).{w,}$

Remarque: changer x , y , z , w dans regex

Edit: réponse regex mise à jour

Edit2: modification ajoutée

Juned Khatri
la source
Votre regex correspond, 12345678êtes-vous sûr qu'il s'agit d'un mot de passe fort ? Veuillez essayer votre expression régulière avant de publier.
Toto
C'est mieux mais ne répond pas à la question, ils veulent 1) 8 caractères. 2) 2 lettres en majuscules. 3) 1 caractère spécial (! @ # $ & *). 4) 2 chiffres (0-9). 5) 3 lettres en minuscules.
Toto
@Toto Pouvez-vous s'il vous plaît partager vos pensées maintenant?
Juned Khatri
Votre regex ne prend pas en compte le fait que les 2 lettres majuscules obligatoires pourraient être séparées par d'autres caractères, même remarque pour les minuscules et les chiffres. La réponse valable est celle qui a été acceptée.
Toto