【问题标题】:Regex to validate password strength正则表达式验证密码强度
【发布时间】:2016-12-17 01:07:48
【问题描述】:

我的密码强度标准如下:

  • 8 个字符长度
  • 2 个大写字母
  • 1 个特殊字符 (!@#$&*)
  • 2个数字(0-9)
  • 3 个小写字母

有人可以给我同样的正则表达式吗?密码必须满足所有条件。

【问题讨论】:

  • 您真的愿意将您的密码安全措施托付给整个互联网吗?
  • @Borealid:发布您的密码策略通常不会显着影响您的安全。如果是这样,那么您的策略是错误的(“只有 passwordhello123 是有效密码!”)。
  • @Joachim Sauer:我不是这个意思。我的意思是,发帖人可能会相信他收到的任何正则表达式。这不是个好主意。
  • 实际上这个正则表达式将在服务代码中,我将测试不同的情况,而不是盲目相信它:)
  • 复杂的密码规则通常不会带来更安全的密码,重要的只是最小长度。人们无法记住大量的强密码,这样的规则会干扰好的密码方案。人们可以非常有创意地绕过这些规则,例如通过使用弱密码,如“Password-2014”。通常,您最终会得到较弱的密码,而不是较强的密码。

标签: regex passwords


【解决方案1】:

您可以使用积极的前瞻性断言进行这些检查:

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

Rubular link

解释:

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

【讨论】:

  • 对于任何希望长度至少为 n 的人,请将 .{8} 替换为 .{n,}
  • +1 以获得完整的解释。我的密码规则不同,但根据您的回答,我可以调整正则表达式。
  • 感谢您描述正则表达式中发生的事情。对于我们这些从未真正熟悉语法的人来说,这是一个很好的学习示例。
  • 我也很欣赏正则表达式的解释。很多次我使用我发现的复杂正则表达式,但并没有真正理解发生了什么。
  • 很好的模式,我想知道为什么不使用量词?至少 1 个特殊字符、1 个数字、1 个特殊字符、8 个字符:^(?=.*([AZ]){1,})(?=.*[!@#$&*]{1,})( ?=.*[0-9]{1,})(?=.*[az]{1,}).{8,100}$
【解决方案2】:

您还应该考虑将一些规则更改为:

  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。我在我的代码中使用它。我喜欢可读性和可重复性,因为当您将来必须返回并更改它时,即在密码策略更改的情况下:)
  • 很棒的解释。恕我直言,这应该是公认的答案。
  • /^(?=.*[az]){3,}(?=.*[AZ]){2,}(?=.*[0-9]){2, }(?=.*[!@#$%^&*()--__+.]){1,}.{8,}$/.test("aA1$bcde") 返回 true,只有 1 个数字和 1 个首都
  • 已更新以包含您的测试用例 @PriyankBolia。查看新的 robulink,它现在应该可以工作了。
  • @Isu_guy 如果超过 Max 出现次数,您希望它失败怎么办?它只是 {min_occurances, max_occurances} ???
【解决方案3】:

您可以使用零长度正向预测来分别指定每个约束:

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

如果您的正则表达式引擎不支持\p 表示法并且纯ASCII 就足够了,那么您可以将\p{Lu} 替换为[A-Z] 并将\p{Ll} 替换为[a-z]

【讨论】:

    【解决方案4】:

    上面给出的答案是完美的,但我建议使用多个较小的正则表达式而不是一个大的。
    拆分长正则表达式有一些优点:

    • 易于书写和阅读
    • 易于调试
    • 轻松添加/删除部分正则表达式

    通常这种方法使代码易于维护

    话虽如此,我分享一段我用 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% 的 CPU 挂起时才会被注意到。示例:^([a-z0-9]+){8,}$(你能看到错误吗?)
    【解决方案5】:

    我建议添加

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

    【讨论】:

      【解决方案6】:

      不幸的是,以上所有正则表达式都对我不起作用。 强密码的基本规则是

      • 至少应包含一个大写字母
      • 至少应包含一个小写字母
      • 应至少包含一个数字
      • 至少应包含一个特殊字符
      • 以及最小长度

      所以,最好的正则表达式是

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

      注意:更改正则表达式中的xyzw

      编辑:更新的正则表达式答案

      Edit2:添加修改

      【讨论】:

      • 您的正则表达式与12345678 匹配,您确定它是strong 密码吗?请在发布之前尝试您的正则表达式。
      • 这更好,但不回答问题,他们想要 1) 8 个字符长度。 2) 2 个大写字母。 3) 1 个特殊字符 (!@#$&*)。 4) 2 个数字 (0-9)。 5) 3 个小写字母。
      • @Toto 您现在可以分享您的想法吗?
      • 您的正则表达式没有考虑到 2 个强制大写字母可以与其他字符分隔,小写和数字的注释相同。有效答案是已被接受的答案。
      【解决方案7】:

      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 - # 不是常规单行注释的开头。此哈希是 comment group 的一部分,该组以 (?# 开头并以 ) 结尾。此正则表达式中没有不平衡的括号。
      【解决方案8】:
      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))
      

      【讨论】:

        【解决方案9】:

        对于 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')
        【解决方案10】:

        另一种解决方案:

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

        【讨论】:

        • 你如何做到这一点,但有一个最大范围?所以像两个大写字母,但不超过两个大写字母?或两个数字,但不超过两个???
        【解决方案11】:

        密码必须满足以下 4 条复杂性规则中的至少 3 条,

        [至少 1 个大写字符 (A-Z) 至少 1 个小写字符 (a-z) 至少 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})

        (?=.[a-z])(?=.[A-Z])(?=.*[0-9])

        (?=.[a-z])(?=.[A-Z])(?=.*[^a-zA-Z0-9])

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

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

        .{10.127}

        【讨论】:

          猜你喜欢
          • 2013-03-18
          • 2010-09-16
          • 2022-12-03
          • 2011-05-06
          • 2016-10-19
          • 2011-03-24
          相关资源
          最近更新 更多