正则表达式验证密码强度

Posted

技术标签:

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

我的密码强度标准如下:

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

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

【问题讨论】:

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

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

    添加更多特殊字符,例如 %、^、(、)、-、_、+ 和句点。我在美国键盘的数字符号上方添加了您错过的所有特殊字符。转义正则表达式使用的那些。 将密码设置为 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,)(?=.*\pLu.*\pLu)(?=.*[!@#$&*])(?=.*[0-9])(?=.*\pLl.*\pLl)

如果您的正则表达式引擎不支持\p 表示法并且纯ASCII 就足够了,那么您可以将\pLu 替换为[A-Z] 并将\pLl 替换为[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'^\S8,$')
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 个)

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

(?!.*(.)\12)

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

【讨论】:

以上是关于正则表达式验证密码强度的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式验证密码强度

js正则表达式之密码强度验证

初学js正则表达式之密码强度验证

密码强度的正则表达式(JavaScript)总结

java中的正则表达式问题 怎么验证密码必须由字母 数字或下划线开头,密码可以随便组合

前端表单验证常用的15个JS正则表达式