正则表达式验证密码强度
Posted
技术标签:
【中文标题】正则表达式验证密码强度【英文标题】:Regex to validate password strength 【发布时间】:2016-12-17 01:07:48 【问题描述】:我的密码强度标准如下:
8 个字符长度 2 个大写字母 1 个特殊字符(!@#$&*)
2个数字(0-9)
3 个小写字母
有人可以给我同样的正则表达式吗?密码必须满足所有条件。
【问题讨论】:
您真的愿意将您的密码安全措施托付给整个互联网吗? @Borealid:发布您的密码策略通常不会显着影响您的安全。如果是这样,那么您的策略是错误的(“只有password
和 hello123
是有效密码!”)。
@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,$
注意:更改正则表达式中的x、y、z、w
编辑:更新的正则表达式答案
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
【讨论】:
以上是关于正则表达式验证密码强度的主要内容,如果未能解决你的问题,请参考以下文章