Regex для проверки надежности пароля


145

Мои критерии надежности пароля следующие:

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

Может ли кто-нибудь дать мне регулярное выражение для того же. Все условия должны выполняться паролем.


2
Вы действительно готовы доверять своим мерам защиты паролей в Интернете в целом?
Borealid

12
@Borealid: публикация политик паролей обычно не должна существенно влиять на вашу безопасность. Если это произойдет, то ваша политика плохо ( «Только passwordи hello123являются действительными паролями!»).
Иоахим Зауэр

3
@Joachim Sauer: Я не это имел в виду. Я имел в виду, что плакат, вероятно, просто будет доверять любому полученному регулярному выражению. Не такая уж хорошая идея.
Borealid

3
На самом деле это регулярное выражение будет в служебном коде, я буду тестировать случаи различий, а не слепо ему доверять :)
Аджай Келкар

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

Ответы:


442

Вы можете выполнить эти проверки, используя утверждения о позитивном прогнозе:

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

97
Для тех, кто хочет длину как минимум n, замените .{8}на.{n,}
NullUserException

15
+1 за полное объяснение. Мои правила для паролей разные, но на основе вашего ответа я могу адаптировать регулярное выражение.
Morvael

15
Спасибо за описание того, что происходит в регулярном выражении. Это служит отличным обучающим примером для тех из нас, кто никогда толком не разбирался в синтаксисе.

4
Я также ценю объяснение регулярного выражения. Часто я использую сложное регулярное выражение, которое я нашел, не понимая, что происходит.
Николас Смит

5
Отличный шаблон, интересно, почему бы не использовать кванторы? Как минимум 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


4

Вам также следует подумать об изменении некоторых из ваших правил на:

  1. Добавьте дополнительные специальные символы, например%, ^, (,), -, _, + и точку. Я добавляю все специальные символы, которые вы пропустили, над цифровыми знаками на клавиатуре США. Избегайте тех, которые использует регулярное выражение.
  2. Сделайте пароль 8 или более символов. Не просто статичное число 8.

С указанными выше улучшениями, а также для большей гибкости и читабельности я бы изменил регулярное выражение на.

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

Основное объяснение

(?=(.*RULE){MIN_OCCURANCES,})     

Каждый блок правил обозначен (? = () {}). Затем правило и количество вхождений могут быть легко определены и протестированы по отдельности, прежде чем объединяться.

Детальное объяснение

^                               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

И, наконец, для целей тестирования вот robulink с указанным выше регулярным выражением


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

Фантастическое объяснение. ИМХО, это должен быть принятый ответ.
Мохамед Вагих,

/ ^ (? =. * [az]) {3,} (? =. * [AZ]) {2,} (? =. * [0-9]) {2,} (? =. * [! @ # $% ^ & * () --__ +.]) {1,}. {8,} $ /. Test ("aA1 $ bcde") возвращает true только с 1
цифрой

Обновлено, чтобы включить ваш тестовый пример @PriyankBolia. См. Новый robulink, который теперь должен работать.
lsu_guy

@Isu_guy, что если вы хотите, чтобы он НЕ УДАЛСЯ, если он превышает максимальное количество случаев? это просто {min_occurances, max_occurances} ???
ennth

1

Решение codaddict работает нормально, но это немного более эффективно: (синтаксис 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 - # не является началом обычного однострочного комментария. Этот хеш является частью группы комментариев, которая начинается с (?#и заканчивается ). В этом регулярном выражении нет несбалансированных пар.
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))

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

как это сделать, но с максимальным диапазоном? так как две заглавные буквы, но НЕ БОЛЬШЕ двух заглавных букв? или две цифры, но НЕ БОЛЬШЕ двух ???
ennth

0

Пароль должен соответствовать минимум 3 из 4 правил сложности,

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

не менее 10 символов

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

не более двух одинаковых символов подряд (например, 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

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