Joi-browser密码校验正则异常 部分符合规则密码验证失败排查
需求说明
需要实现的密码校验规则如下:
- 至少包含4个数字
- 至少包含1个小写字母
- 至少包含1个大写字母
- 至少包含1个特殊符号(范围为!@#$%^&*)
- 密码总长度至少为8位
原有错误代码
基于joi-browser编写的初始校验逻辑:
password: Joi.string() .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]+4)(?=.*[!@#$%^&*])(?=.{8,})/) .required() .min(8),
运行时出现校验逻辑异常:密码Josh1995*无法通过校验,密码Ja1234**可正常通过。
问题根因
核心错误出在正则的数字校验部分,同时存在一个特殊字符匹配的隐藏bug:
- 数字校验规则
(?=.*[0-9]+4)写法完全错误:该正向预查的实际匹配逻辑是*「字符串中存在任意位置,其后跟随任意数量的任意字符、1个及以上连续数字、字面量字符4」*,完全不符合「至少包含4个数字」的需求。- 测试用例
Ja1234**中刚好存在连续数字123后紧跟字面量4的片段,刚好命中错误规则,因此可以通过校验 - 测试用例
Josh1995*中的数字片段为1995,数字后没有紧跟字面量4,因此无法命中错误规则,校验不通过
- 测试用例
- 特殊字符匹配部分写了HTML转义字符
&,实际运行时会匹配字面量字符串amp;,无法正确匹配特殊符号& - 正则中已经写了长度校验
(?=.{8,}),又额外调用Joi的.min(8)方法,属于重复校验,无功能错误但属于冗余代码。
修正方案
将数字校验的正向预查改为(?=(.*\d){4,}),该规则的逻辑是*「字符串中至少出现4次数字(不需要连续)」*,同时修正特殊字符的转义错误,移除冗余的长度正则校验即可,修正后代码如下:
password: Joi.string() .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=(.*\d){4,})(?=.*[!@#$%^&*])/) .required() .min(8),
内容的提问来源于stack exchange,提问作者Omer
相关产品推荐
相关产品推荐

