正则表达式包含拉丁字符

4

我有一个正则表达式来确保密码包含大小写字符并且仅限于少数符号:

^(?:(?=[^a-z]*[a-z])(?=[^A-Z]*[A-Z])(?=.*[$@$!%*?&,;.:-_])[A-Za-z\d$@$!%*?&,;.:-_]+)?$

注意:它允许空密码。我正在用另一种方式进行检查。

但是,它不允许使用如 ç、á、õ 等拉丁字符。

如何添加这种类型的字符?

更新

我正在尝试创建一个与 Microsoft 选项同步的密码验证正则表达式,例如:

RequireDigit (Default = true) 
  Requires a number between 0-9 in the password.

RequireNonAlphanumeric (Default = true)     
  Requires a non-alphanumeric character in the password.

RequireUppercase (Default = true)   
  Requires an upper case character in the password.

RequireLowercase (Default = true)   
  Requires a lower case character in the password.

RequiredUniqueChars (Default = 1)   
  Requires the number of distinct characters in the password

微软文档:https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-configuration?tabs=aspnetcore2x

因此,我希望有一个正则表达式块,这样我可以通过添加或删除规则以及进行任意组合来轻松更改它。

这样说是否让您明白了呢?


2
不要限制符号。同时,使用字符类\p{Ll}表示任何脚本中的小写字母。微软文档涵盖了这一点。 - ctwheels
4
密码设置的规则越多,攻击就越有针对性。不要过滤任何字符,因为密码已经进行了加盐和哈希处理,对吧? - maccettura
1
如果出于某种奇怪的原因,您必须验证密码,请至少允许任何脚本中的任何字符工作,并且不要将字符限制为特定集合:^(?=\P{Ll}*\p{Ll})(?=\P{Lu}*\p{Lu})(?=\P{N}*\p{N})(?=.*[^\p{L}\p{N}\p{C}]).{8,}$ - ctwheels
然而,现在您已经限制了可以输入的密码(这表明您正在以明文存储,这是绝对不允许的)。您为攻击者提供了一个清晰的规则集来过滤他们的字典。必须包含大写和小写字母?好的,现在攻击者已经排除了x个字典项。不能包含拉丁字符?好的,现在他们进一步减少了他们的字典。您所做的可能看起来像是增加了安全性,但最终却是在降低它。 - maccettura
@maccetture 我正在对密码进行哈希处理。我刚刚更新了我的问题以更好地解释我在尝试做什么。 - Miguel Moura
显示剩余6条评论
1个回答

3

概述

通常来说,限制密码是不好的做法,因此如果这是意图,请勿使用以下正则表达式。无论如何,我理解有些人至少希望确保存在一些字符集(大写、小写、数字、符号等),并且在需要时存在特殊情况。下面的正则表达式确保在至少8个字符的字符串中存在至少一个小写字母、大写字母、数字和符号(任何语言/脚本)。

正如问题下面的评论所建议的那样,将密码限制为特定字符集或特定格式只会带来麻烦。正如@maccettura所建议的那样,攻击者可以过滤字典攻击并消除许多不符合您密码格式的字典项。例如,编写[A-Za-z\d$@$!%*?&,;.:-_],攻击者可以简单地删除包含列表中以外字符的任何密码。该列表仅包含75个字符。有多少个75个字符的排列组合?对于长度为8个字符的密码,排列组合数为680,240,886,192,000(如果我们删除不符合下面正则表达式的密码,则排列组合数会更少)。您的CPU需要多长时间才能破解密码?

请参阅以下有关密码的StackExchange帖子:

其他文章:

代码

在此处查看使用的正则表达式

^(?=\P{Ll}*\p{Ll})(?=\P{Lu}*\p{Lu})(?=\P{N}*\p{N})(?=.*[^\p{‌​L}\p{N}\p{C}]).{8,}$

解释

\p{x}代表由x指定的Unicode通用类别或命名块

  • ^ 断言位于行首
  • (?=\P{Ll}*\p{Ll}) 确保任何一种书写中至少存在一个小写字母
  • (?=\P{Lu}*\p{Lu}) 确保任何一种书写中至少存在一个大写字母
  • (?=\P{N}*\p{N}) 确保任何一种书写中至少存在一个数字字符
  • (?=.*[^\p{‌​L}\p{N}\p{C}]) 确保除字母、数字和控制字符外还存在其他字符
  • .{8,} 确保密码长度至少为8个字符(上限未限制)
  • $ 断言位于行尾

请问在您的前瞻中使用否定有什么优势?例如,使用(?=\P{Ll}*\p{Ll})与使用(?=.*\p{Ll})相比是否有任何优势? - JackPRead
1
@JackPRead 这样做会使它稍微快一点。看看我原始正则表达式的步骤数这里,以及当我替换单个否定集合时的步骤数这里。步骤增加了1。或者,也可以使用.*?(没有额外的步骤),但在找不到匹配项的情况下,.*?将需要更多的步骤(如此处所示)才能完成,而\P{Ll}则需要更少的步骤(如此处所示),因为它会回溯。 - ctwheels
经过思考,这完全说得通。谢谢。实际上,如果你将通配符的量词设为懒惰模式,也可以得到相同的结果。示例在此。不过,如果搜索一个大字符串的话,我认为你的方法可能仍然更好。 - JackPRead
@JackPRead 我更新了之前的评论,加入了懒惰量词。虽然它确实表明它可能是等效的,但当模式无法匹配字符串时,它实际上会变慢(在这种情况下是27步而不是4步)。这是由于回溯造成的。 - ctwheels
一些小知识……这可能是有用的,也可能不是,我不确定。在这9763个字符中,它匹配 [^\p{L}\p{N}\p{C}],同时也包括 \p{Block=Combining_Diacritical_Marks} U+300 - U+36f。 - user557597
@sln 个人而言,我会允许它们,因为为什么要限制呢?但你可以将 \p{M} 添加到否定集中。 - ctwheels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接