密码强度校验正则的组合思路
「至少包含大写、小写、数字、符号各一个」这类规则最适合用零宽前瞻组合:每个前瞻只负责检查某一类字符是否存在,彼此顺序无关,整条模式在长度约束下依次检查完就放行。要清楚它的边界:正则能判断字符类别是否出现,判断不了密码好不好猜。
基本信息
| 基本结构 | 多个 (?=…) 前瞻叠加,最后一个字符集加量词负责整体长度 |
|---|---|
| 顺序无关 | 前瞻只做检查不消耗字符,因此四类字符的先后位置不影响结果 |
| 点号限制 | 点号默认不匹配换行,需要允许换行时改用显式的空白与非空白组合 |
| 表达力边界 | 无法表达「不含用户名」「不在弱口令表」「熵足够」这类判断 |
典型使用场景
- 注册密码规则:在表单层与接口层各校验一次,保证前后端判定一致
- 密码修改流程:新密码校验通过后再进入哈希与入库环节
- 批量导入账号:把不合规的初始密码列入待处理清单,而不是直接忽略
- 合规自测:按内部安全基线检查存量账号是否满足基本字符类别要求
- 前端即时提示:给出缺哪一类字符的明确反馈,减少反复提交
组合前瞻写法
组合前瞻写法
# 至少一个小写、一个大写、一个数字、一个非字母数字字符,长度 10 到 64
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^A-Za-z0-9])\S{10,64}$
# 允许任意非空白字符时,用点号会漏掉换行,需要显式组合
^(?=[\s\S]*[a-z])(?=[\s\S]*[A-Z])(?=[\s\S]*\d)[\s\S]{10,64}$
# 判断缺哪一类字符:用多个独立检查给出具体提示,而不是只返回失败
missing = [n for n, ok in (('小写', re.search(r'[a-z]', pw)),) if not ok]
# 强度评分不要用正则,交给专门库评估
# zxcvbn 类库会结合字典与常见模式给出分档结果常见需求的写法与局限
| 需求 | 正则写法 | 局限 |
|---|---|---|
| 四类字符各至少一个 | 多个前瞻叠加 | 不问字符是否重复或可预测 |
| 长度区间 | 末段字符集加量词 | 上限要设,防止超长输入 |
| 不含空格 | 用非空白字符集 | 会连带排除其他空白符 |
| 不与用户名相同 | 无法可靠表达 | 需要代码比较 |
| 不在弱口令表 | 无法表达 | 需要字典或库 |
NIST SP 800-63B 的建议是以长度下限与弱口令黑名单为主,谨慎使用强制组合规则:过于严格的组合要求会促使用户选择形如首字母大写加感叹号结尾的可预测变体,实际强度反而下降。
长度上限必须设置:哈希函数对超长输入的开销会明显上升,缺少上限的密码字段可能被用来消耗服务端资源;使用 bcrypt 一类算法时还要注意其输入长度限制,超出部分会被截断。