Regex для перевірки міцності пароля


142

Мої критерії надійності пароля наведені нижче:

  • 8 символів
  • 2 літери у верхньому регістрі
  • 1 Спеціальний персонаж (!@#$&*)
  • 2 числівники (0-9)
  • 3 букви в нижній регістрі

Може хтось, будь ласка, дайте мені регекс для того ж. Усі умови повинні відповідати паролем.


2
Ви дійсно готові довіряти своїм заходам захисту пароля в Інтернеті взагалі?
Borealid

12
@Borealid: публікація політик щодо паролів, як правило, не повинна суттєво впливати на вашу безпеку. Якщо це так, то ваша політика погана ("Тільки passwordі hello123справжні паролі!").
Йоахім Зауер

3
@Joachim Sauer: Це я не мав на увазі. Я мав на увазі те, що плакат, ймовірно, просто збирається довіряти тому, що він отримає. Не така гарна ідея.
Borealid

3
Насправді цей регулярний вимір буде в коді обслуговування, я буду тестувати на різні випадки, а не сліпо йому довіряти :)
Ajay Kelkar

9
Складні правила паролів, як правило, не призводять до більш безпечних паролів, важливим є лише мінімальна довжина. Люди не можуть згадати багато надійних паролів, і такі правила можуть заважати хорошим парольним схемам. Люди можуть бути дуже винахідливими, щоб обійти такі правила, наприклад, використовуючи слабкі паролі, наприклад "Пароль-2014". Часто ви стикаєтесь із слабшими паролями замість більш сильних.
martinstoeckli

Відповіді:


428

Ви можете зробити ці перевірки, використовуючи позитивні твердження вперед:

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

Рулонна ланка

Пояснення:

^                         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.

92
Для всіх, хто хоче хоча б тривалості n, замініть .{8}на.{n,}
NullUserException

14
+1 для повного пояснення. Мої правила пароля різні, але на основі вашої відповіді я можу адаптувати регулярний вираз.
Morvael

14
Дякую за опис того, що відбувається в регулярному вираженні. Це слугує чудовим прикладом навчання для тих із нас, хто ніколи насправді не вдавався в синтаксис.

4
Я також вдячний за пояснення регексу. Я багато разів використовую складний регулярний вираз, який я знайшов, не розуміючи, що відбувається.
Ніколас Сміт

4
Чудова картина, мені цікаво, чому б не використовувати квантори? Принаймні 1 спеціальний, 1 номер, 1 спеціальний знак, 8 символів: ^ (? =. * ([AZ]) {1,}) (? =. * [! @ # $ & *] {1,}) ( ? =. * [0-9] {1,}) (? =. * [Az] {1,}). {8,100} $
RockOnGom

11

Ви можете використовувати позитивні огляди нульової довжини, щоб вказати кожне з ваших обмежень окремо:

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

Якщо ваш регекс-движок не підтримує \pпозначення і достатньо чистого ASCII, то його можна замінити \p{Lu}на [A-Z]і \p{Ll}на [a-z].


8

Відповіді, наведені вище, ідеальні, але я пропоную використовувати кілька менших регулярних виразів, а не великих.
Розщеплення довгого регексу має деякі переваги:

  • легкість писати і читати
  • легкість налагодження
  • легкість додавання / видалення частини регулярного вираження

Як правило, цей підхід зберігає код легко досяжним .

Сказавши це, я ділюся фрагментом коду, який я пишу в Swift як приклад:

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 []
        }
    }
}

Також, використовуючи складний регулярний вираз, як описано вище, дуже легко відкрити себе для катастрофічного зворотного відстеження ( regular-expressions.info/catastrophic.html ). Це може пройти непомітно, поки одного дня ваш сервер не зависне зі 100% процесором, оскільки користувач використовував "дивний" пароль. Приклад: ^ ([a-z0-9] +) {8,} $ (ви бачите помилку?)
aKzenT

5

Я б запропонував додати

(?!.*pass|.*word|.*1234|.*qwer|.*asdf) exclude common passwords

1

рішення кодового рішення працює чудово, але це трохи ефективніше: (синтаксис 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)

Заперечені класи символів споживають усе, що відповідає бажаному символу, за один крок, вимагаючи нульового зворотного відстеження. (Рішення крапки зірки працює чудово, але вимагає деякого зворотного відстеження.) Звичайно, з короткими цільовими рядками, такими як паролі, це підвищення ефективності буде незначним.


Не могли б ви перевірити, чи правильно це? Я сумніваюсь через відкриття круглої дужки в першому рядку між потрійним подвійним котируванням та знаком питання. Я бачу, що коментар Python (хеш) пізніше. Я не можу побачити, як закриваюча кругла дужка кореспондента біля кінцевого якоря (знак долара). Слід зазначити, що я не регенерований фахівець.
lospejos

@lospejos - # не є початковим регулярним коментарем у одному рядку. Цей хеш є частиною групи коментарів, яка починається з а (?#і закінчується а ). У цьому регексе немає неврівноважених паронів.
вершник

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))

1

@ рішення кодексу буде спрацьовувати.

Слід також розглянути можливість зміни деяких своїх правил на:

  1. Додайте більше спеціальних символів, тобто%, ^, (,), -, _, + та період. Я додаю всі спеціальні символи, які ви пропустили над цифровими знаками на американських клавіатурах. Уникнути тих, які використовує регулярний вираз.
  2. Введіть пароль 8 або більше символів. Не просто статичне число 8.

З урахуванням вищезгаданих удосконалень, а також для більшої гнучкості та читабельності, я би змінив регулярний вираз.

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

Основне пояснення

(?=.*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

Детальне пояснення

^                             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

І нарешті, для цілей тестування тут є перемичка з вищевказаним виразним знаком


Дякую @AFract. Я використовую це у своєму коді. Мені подобається читабельність та здатність до повторення, бо коли вам доведеться повернутися назад і змінити його в майбутньому, тобто у випадку зміни політики щодо пароля :)
lsu_guy

0

Для PHP це прекрасно працює!

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

в цьому випадку результат вірний

Думки для @ridgerunner


чому ні return preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 'CaSu4Li8')?
aloisdg переходить на codidact.com

0

Ще одне рішення:

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()

0

Пароль повинен відповідати щонайменше 3 із наступних 4 правил складності,

[принаймні 1 верхній регістр (AZ) принаймні 1 малий символ (az) принаймні 1 цифра (0-9) принаймні 1 спеціальний символ - не забудьте ставитися до місця як до спеціальних символів]

принаймні 10 символів

максимум 128 символів

не більше 2 однакових символів поспіль (наприклад, 111 не дозволено)

'^ (?!. (.) \ 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}


0

Наведене вище регекс, на жаль, не працював для мене. Основні правила сильного пароля

  • Повинен містити принаймні велику літеру
  • Повинен містити хоча б маленьку букву
  • Слід містити принаймні кількість
  • Повинен містити принаймні спеціальний символ
  • І мінімальна довжина

Отже, Best Regex був би

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

Наведений вище вираз має мінімальну довжину 8. Ви можете змінити його від {8,} до { any_number ,}

Зміна правил?

скажімо, що ви хочете, щоб мінімум x символів малими літерами, y символами великої літери, z цифрами символів, загальною мінімальною довжиною w . Потім спробуйте нижче регулярного вираження

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

Примітка: Змініть x , y , z , w у регулярному вираженні

Редагувати: оновлена ​​відповідь на регулярний вираз

Edit2: Додано модифікацію


Ваш регекс збігається. 12345678Ви впевнені, що це надійний пароль? Будь ласка, спробуйте свій регулярний гекс перед публікацією.
Toto

Це краще, але не відповідає на питання, вони хочуть 1) довжиною 8 символів. 2) 2 літери у верхньому регістрі. 3) 1 спеціальний персонаж (! @ # $ & *). 4) 2 числівники (0-9). 5) 3 букви в нижній регістрі.
Toto

@Toto Чи можете ви зараз поділитися своїми думками?
Juned Khatri

Ваш регулярний вираз не враховує, що дві обов'язкові великі літери можна розділити з іншими символами, однакове зауваження для малих і малих цифр. Дійсною є відповідь, яку було прийнято.
Toto
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.