Regex to validate password strength

后端 未结 11 764
天涯浪人
天涯浪人 2020-11-22 02:13

My password strength criteria is as below :

  • 8 characters length
  • 2 letters in Upper Case
  • 1 Special Character (!@#$&*)
  • <
相关标签:
11条回答
  • 2020-11-22 03:01

    I would suggest adding

    (?!.*pass|.*word|.*1234|.*qwer|.*asdf) exclude common passwords
    
    0 讨论(0)
  • 2020-11-22 03:03

    For PHP, this works fine!

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

    in this case the result is true

    Thsks for @ridgerunner

    0 讨论(0)
  • 2020-11-22 03:04

    Answers given above are perfect but I suggest to use multiple smaller regex rather than a big one.
    Splitting the long regex have some advantages:

    • easiness to write and read
    • easiness to debug
    • easiness to add/remove part of regex

    Generally this approach keep code easily maintainable.

    Having said that, I share a piece of code that I write in Swift as example:

    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 []
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:04

    You should also consider changing some of your rules to:

    1. Add more special characters i.e. %, ^, (, ), -, _, +, and period. I'm adding all the special characters that you missed above the number signs in US keyboards. Escape the ones regex uses.
    2. Make the password 8 or more characters. Not just a static number 8.

    With the above improvements, and for more flexibility and readability, I would modify the regex to.

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

    Basic Explanation

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

    Detailed Explanation

    ^                               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
    

    And lastly, for testing purposes here is a robulink with the above regex

    0 讨论(0)
  • 2020-11-22 03:13

    You can do these checks using positive look ahead assertions:

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

    Rubular link

    Explanation:

    ^                         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.
    
    0 讨论(0)
提交回复
热议问题