Compare commits

...

3 Commits

Author SHA1 Message Date
Looly
4162c519b7 修复PasswdStrength.checkindexOf逻辑问题(pr#4114@Github)。 2025-10-24 16:00:20 +08:00
Golden Looly
b136d81720 Merge pull request #4114 from sunshineflymeat/hutool-1024
feat:修复PasswdStrength.check方法检测密码强度等级逻辑有误问题
2025-10-24 15:48:06 +08:00
zwm
8469fd0c49 feat:修复PasswdStrength.check方法检测密码强度等级逻辑有误问题 2025-10-24 13:53:22 +08:00
3 changed files with 59 additions and 34 deletions

View File

@@ -1,7 +1,7 @@
# 🚀Changelog
-------------------------------------------------------------------------------------------------------------
# 5.8.42(2025-10-23)
# 5.8.42(2025-10-24)
### 🐣新特性
* 【core 】 `ListUtil`增加`zip`方法pr#4052@Github
@@ -13,6 +13,7 @@
* 【jwt 】 修复verify方法在定义alg为`none`时验证失效问题issue#4105@Github
* 【extra 】 修复`JschSessionPool.remove`逻辑错误问题。
* 【db 】 修复`Dialect.psForCount`未传入Wrapper导致大小写问题issue#ID39G9@Gitee)。
* 【core 】 修复`PasswdStrength.check`indexOf逻辑问题pr#4114@Github)。
-------------------------------------------------------------------------------------------------------------
# 5.8.41(2025-10-12)

View File

@@ -29,13 +29,13 @@ public class PasswdStrength {
* 简单密码字典
*/
private final static String[] DICTIONARY = {"password", "abc123", "iloveyou", "adobe123", "123123", "sunshine",
"1314520", "a1b2c3", "123qwe", "aaa111", "qweasd", "admin", "passwd"};
"1314520", "a1b2c3", "123qwe", "aaa111", "qweasd", "admin", "passwd"};
/**
* 数字长度
*/
private final static int[] SIZE_TABLE = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
Integer.MAX_VALUE};
Integer.MAX_VALUE};
/**
* 检查密码的健壮性
@@ -65,48 +65,48 @@ public class PasswdStrength {
}
if (len > 4 && countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
level++;
}
if (len > 6 && countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 || countLetter(passwd, CHAR_TYPE.NUM) > 0
&& countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0 || countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 || countLetter(passwd, CHAR_TYPE.NUM) > 0
&& countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0
|| countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0 || countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
level++;
}
if (len > 8 && countLetter(passwd, CHAR_TYPE.NUM) > 0 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) > 0
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) > 0 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) > 0) {
level++;
}
if (len > 6 && countLetter(passwd, CHAR_TYPE.NUM) >= 3 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 3
|| countLetter(passwd, CHAR_TYPE.NUM) >= 3 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3
|| countLetter(passwd, CHAR_TYPE.NUM) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
|| countLetter(passwd, CHAR_TYPE.NUM) >= 3 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3
|| countLetter(passwd, CHAR_TYPE.NUM) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3
|| countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 3 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
level++;
}
if (len > 8 && countLetter(passwd, CHAR_TYPE.NUM) >= 2 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 || countLetter(passwd, CHAR_TYPE.NUM) >= 2
&& countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.NUM) >= 2 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2 || countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 || countLetter(passwd, CHAR_TYPE.NUM) >= 2
&& countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2
|| countLetter(passwd, CHAR_TYPE.NUM) >= 2 && countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2 || countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
level++;
}
if (len > 10 && countLetter(passwd, CHAR_TYPE.NUM) >= 2 && countLetter(passwd, CHAR_TYPE.SMALL_LETTER) >= 2
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
&& countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) >= 2 && countLetter(passwd, CHAR_TYPE.OTHER_CHAR) >= 2) {
level++;
}
@@ -124,19 +124,21 @@ public class PasswdStrength {
}
}
// decrease points
if ("abcdefghijklmnopqrstuvwxyz".indexOf(passwd) > 0 || "ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(passwd) > 0) {
// 判断passwd是否为连续字母a-z/A-Z的完整子串
if ("abcdefghijklmnopqrstuvwxyz".contains(passwd) || "ABCDEFGHIJKLMNOPQRSTUVWXYZ".contains(passwd)) {
level--;
}
if ("qwertyuiop".indexOf(passwd) > 0 || "asdfghjkl".indexOf(passwd) > 0 || "zxcvbnm".indexOf(passwd) > 0) {
// 判断passwd是否为键盘连续序列的完整子串
if ("qwertyuiop".contains(passwd) || "asdfghjkl".contains(passwd) || "zxcvbnm".contains(passwd)) {
level--;
}
if (StrUtil.isNumeric(passwd) && ("01234567890".indexOf(passwd) > 0 || "09876543210".indexOf(passwd) > 0)) {
// 判断passwd是否为纯数字弱密码升序或降序的完整子串
if (StrUtil.isNumeric(passwd) && ("01234567890".contains(passwd) || "09876543210".contains(passwd))) {
level--;
}
if (countLetter(passwd, CHAR_TYPE.NUM) == len || countLetter(passwd, CHAR_TYPE.SMALL_LETTER) == len
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) == len) {
|| countLetter(passwd, CHAR_TYPE.CAPITAL_LETTER) == len) {
level--;
}
@@ -172,6 +174,7 @@ public class PasswdStrength {
}
}
// 检测密码是否为简单密码字典中的弱密码或包含字典弱密码片段
for (String s : DICTIONARY) {
if (passwd.equals(s) || s.contains(passwd)) {
level--;
@@ -201,7 +204,7 @@ public class PasswdStrength {
}
/**
* Get password strength level, includes easy, midium, strong, very strong, extremely strong
* 获取密码强度等级, 包括 easy, medium, strong, very strong, extremely strong
*
* @param passwd 密码
* @return 密码等级枚举
@@ -232,8 +235,7 @@ public class PasswdStrength {
}
/**
* Check character's type, includes num, capital letter, small letter and other character.
* 检查字符类型
* 检查字符类型,包括数字、大写字母、小写字母及其他字符
*
* @param c 字符
* @return 类型

View File

@@ -1,8 +1,9 @@
package cn.hutool.core.text;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class PasswdStrengthTest {
@Test
public void strengthTest(){
@@ -15,4 +16,25 @@ public class PasswdStrengthTest {
String passwd = "9999999999999";
assertEquals(0, PasswdStrength.check(passwd));
}
@Test
public void consecutiveLettersTest() {
// 测试连续小写字母会被降级
assertEquals(0, PasswdStrength.check("abcdefghijklmn"));
// 测试连续大写字母会被降级
assertEquals(0, PasswdStrength.check("ABCDEFGHIJKLMN"));
}
@Test
public void dictionaryWeakPasswordTest() {
// 测试包含简单密码字典中的弱密码
assertEquals(0, PasswdStrength.check("password"));
assertEquals(3, PasswdStrength.check("password2"));
}
@Test
public void numericSequenceTest() {
assertEquals(0, PasswdStrength.check("01234567890"));
assertEquals(0, PasswdStrength.check("09876543210"));
}
}