Regex để xác nhận độ mạnh của mật khẩu


142

Tiêu chí độ mạnh mật khẩu của tôi là như sau:

  • Độ dài 8 ký tự
  • 2 chữ cái in hoa
  • 1 nhân vật đặc biệt (!@#$&*)
  • 2 chữ số (0-9)
  • 3 chữ cái in thường

Ai đó có thể xin vui lòng cho tôi regex cho cùng. Tất cả các điều kiện phải được đáp ứng bằng mật khẩu.


2
Bạn có thực sự sẵn sàng tin tưởng các biện pháp bảo mật mật khẩu của bạn với Internet không?
Borealid

12
@Borealid: xuất bản chính sách mật khẩu của bạn thường không ảnh hưởng đáng kể đến bảo mật của bạn. Nếu đúng như vậy, thì chính sách của bạn rất tệ ("Chỉ passwordhello123là mật khẩu hợp lệ!").
Joachim Sauer

3
@Joachim Sauer: Đó không phải là ý tôi. Điều tôi muốn nói là người đăng có lẽ sẽ tin tưởng bất cứ thứ gì mà anh ta nhận được. Không phải là một ý tưởng tốt.
Borealid

3
Trên thực tế regex này sẽ có trong mã dịch vụ, tôi sẽ kiểm tra các trường hợp khác không tin tưởng một cách mù quáng :)
Ajay Kelkar

9
Các quy tắc mật khẩu phức tạp thường sẽ không dẫn đến mật khẩu an toàn hơn, quan trọng chỉ là độ dài tối thiểu. Mọi người không thể nhớ hàng tấn mật khẩu mạnh và các quy tắc như vậy có thể can thiệp vào các chương trình mật khẩu tốt. Mọi người có thể rất sáng tạo để bỏ qua các quy tắc như vậy, ví dụ: bằng cách sử dụng mật khẩu yếu như "Mật khẩu-2014". Thường thì bạn kết thúc với mật khẩu yếu hơn thay vì mật khẩu mạnh hơn.
martinstoeckli

Câu trả lời:


427

Bạn có thể thực hiện các kiểm tra này bằng cách sử dụng các xác nhận tích cực về phía trước:

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

Liên kết rubular

Giải trình:

^                         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
Đối với bất kỳ ai muốn có độ dài ít nhất n, hãy thay thế .{8}bằng.{n,}
NullUserException

14
+1 cho một lời giải thích hoàn chỉnh. Quy tắc mật khẩu của tôi là khác nhau nhưng dựa trên câu trả lời của bạn, tôi có thể điều chỉnh regex.
Morvael

14
Cảm ơn bạn đã mô tả những gì đang xảy ra trong regex. Đây là một ví dụ học tập tuyệt vời cho những người trong chúng ta chưa bao giờ thực sự hiểu về cú pháp.

4
Tôi cũng đánh giá cao sự giải thích của regex. Nhiều lần tôi sử dụng regex phức tạp mà tôi tìm thấy, mà không thực sự hiểu chuyện gì đang xảy ra.
Nicholas Smith

4
Mô hình tuyệt vời, tôi tự hỏi tại sao không sử dụng định lượng? Ít nhất 1 đặc biệt, 1 số, 1 char đặc biệt, 8 ký tự: ^ (? =. * ([AZ]) {1,}) (? =. * [! @ # $ & *] {1,}) ( ? =. * [0-9] {1,}) (? =. * [Az] {1,}). {8,100} $
RockOnGom

11

Bạn có thể sử dụng các hướng nhìn tích cực có độ dài bằng không để chỉ định riêng từng ràng buộc của mình:

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

Nếu công cụ regex của bạn không hỗ trợ \pký hiệu và ASCII thuần túy là đủ, thì bạn có thể thay thế \p{Lu}bằng [A-Z]\p{Ll}bằng [a-z].


8

Câu trả lời được đưa ra ở trên là hoàn hảo nhưng tôi đề nghị sử dụng nhiều regex nhỏ hơn là một lớn.
Tách regex dài có một số lợi thế:

  • dễ dàng để viết và đọc
  • dễ dàng để gỡ lỗi
  • dễ dàng thêm / xóa một phần của regex

Nói chung cách tiếp cận này giữ mã dễ dàng duy trì .

Phải nói rằng, tôi chia sẻ một đoạn mã mà tôi viết trong Swift làm ví dụ:

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

Ngoài ra, khi sử dụng regex phức tạp như trên, bạn có thể dễ dàng mở chính mình cho việc quay lại thảm khốc (chính quy-expressions.info / catastrophic.html ). Điều này có thể không được chú ý cho đến một ngày máy chủ của bạn bị treo với CPU 100% vì người dùng đã sử dụng mật khẩu "lạ". Ví dụ: ^ ([a-z0-9] +) {8,} $ (bạn có thể thấy lỗi không?)
aKzenT

5

Tôi sẽ đề nghị thêm

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

1

Giải pháp của codaddict hoạt động tốt, nhưng giải pháp này hiệu quả hơn một chút: (cú pháp 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)

Các lớp nhân vật bị phủ định tiêu thụ mọi thứ cho đến ký tự mong muốn trong một bước duy nhất, yêu cầu quay lại bằng không. (Giải pháp sao chấm chỉ hoạt động tốt, nhưng không yêu cầu quay lại.) Tất nhiên với các chuỗi mục tiêu ngắn như mật khẩu, cải thiện hiệu quả này sẽ không đáng kể.


Bạn có thể vui lòng kiểm tra nếu nó là chính xác? Tôi nghi ngờ vì mở dấu ngoặc tròn ở dòng đầu tiên giữa ba doublequote và dấu hỏi. Tôi có thể thấy rằng bình luận Python (băm) là sau. Tôi không thể thấy dấu ngoặc tròn đóng của phóng viên gần neo cuối (ký hiệu đô la). Nên đề cập đến tôi không phải là một regex profy.
lospejos

@lospejos - # không phải là khởi đầu của một nhận xét một dòng thông thường. Hàm băm này là một phần của nhóm nhận xét bắt đầu bằng a (?#và kết thúc bằng a ). Không có parens không cân bằng trong regex này.
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))

1

Giải pháp của @ codaddict sẽ hoạt động.

Bạn cũng nên xem xét thay đổi một số quy tắc của mình thành:

  1. Thêm các ký tự đặc biệt hơn, ví dụ%, ^, (,), -, _, + và dấu chấm. Tôi đang thêm tất cả các ký tự đặc biệt mà bạn đã bỏ lỡ phía trên các ký hiệu số trong bàn phím Hoa Kỳ. Thoát khỏi những người sử dụng regex.
  2. Tạo mật khẩu 8 ký tự trở lên. Không chỉ là một số 8 tĩnh.

Với những cải tiến ở trên, và để linh hoạt hơn và dễ đọc hơn, tôi sẽ sửa đổi regex thành.

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

Giải thích cơ bản

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

Giải thích chi tiết

^                             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

Và cuối cùng, cho mục đích thử nghiệm ở đây là một robulink với regex ở trên


Cảm ơn @AFract. Tôi đang sử dụng nó trong mã của tôi. Tôi thích khả năng đọc và khả năng lặp lại, vì khi bạn phải quay lại và thay đổi nó trong tương lai, tức là trong trường hợp thay đổi chính sách mật khẩu :)
lsu_guy

0

Đối với PHP, điều này hoạt động tốt!

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

trong trường hợp này kết quả là đúng

Thsks cho @ridgerunner


tại sao không return preg_match("/^(?=(?:[^A-Z]*[A-Z]){2})(?=(?:[^0-9]*[0-9]){2}).{8,}$/", 'CaSu4Li8')?
aloisdg chuyển đến codidact.com

0

Giải pháp khác:

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

Mật khẩu phải đáp ứng ít nhất 3 trong số 4 quy tắc phức tạp sau đây,

[ít nhất 1 ký tự viết hoa (AZ) ít nhất 1 ký tự chữ thường (az) ít nhất 1 chữ số (0-9) ít nhất 1 ký tự đặc biệt - đừng quên coi không gian là ký tự đặc biệt]

ít nhất 10 ký tự

nhiều nhất là 128 ký tự

không quá 2 ký tự giống nhau trong một hàng (ví dụ: 111 không được phép)

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

Tất cả các regex trên không may không làm việc cho tôi. Các quy tắc cơ bản của mật khẩu mạnh là

  • Nên chứa ít nhất một chữ in hoa
  • Nên chứa ít nhất một chữ cái nhỏ
  • Nên chứa ít nhất một số
  • Nên chứa ít nhất một ký tự đặc biệt
  • Và chiều dài tối thiểu

Vì vậy, Regex tốt nhất sẽ là

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

Regex ở trên có độ dài tối thiểu là 8. Bạn có thể thay đổi nó từ {8,} thành { any_number ,}

Sửa đổi trong quy tắc?

giả sử bạn muốn tối thiểu x ký tự chữ nhỏ, ký tự y chữ cái, số ký tự z , Tổng chiều dài tối thiểu w . Sau đó thử dưới regex

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

Lưu ý: Thay đổi x , y , z , w trong regex

Chỉnh sửa: Cập nhật câu trả lời regex

Edit2: Đã thêm sửa đổi


Regex của bạn phù hợp với 12345678bạn có chắc chắn đó là một mật khẩu mạnh ? Xin vui lòng, hãy thử regex của bạn trước khi đăng.
Toto

Điều đó tốt hơn nhưng không trả lời câu hỏi, họ muốn có 1) 8 ký tự. 2) 2 chữ cái in hoa. 3) 1 Nhân vật đặc biệt (! @ # $ & *). 4) 2 chữ số (0-9). 5) 3 chữ cái in thường.
Toto

@Toto Bạn có thể vui lòng chia sẻ suy nghĩ của bạn bây giờ?
Juned Khatri

Regex của bạn không tính đến việc 2 chữ cái Uppercase bắt buộc có thể được phân tách bằng các ký tự khác, cùng một nhận xét cho chữ thường và chữ số. Câu trả lời hợp lệ là câu trả lời đã được chấp nhận.
Toto
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.