工具介绍
公司在做认证系统时,由于安全需要,屏蔽掉弱密码,需要检测用户输入的密码强度。计算方法参考http://www.passwordmeter.com/ 的计算方法,但passwordmeter本身计算存在些许错误,且无java版本,后端无法对密码进行二次校验(后端不信任前端任何验证)。于是开发了这个密码强度检验函数。
校验函数通过100W随机密码测试,100W条数据中无一条错误,如果你在测试过程中发现错误,请评论区留下测试结果不一致的密码字符串,这边将会修复。
- 感谢 上海智隆信息 张晋荣 提供的帮助
验证算法
说明: 表格中 n代表存在该项目出现的次数, len代表密码总长度
密码最低要求:
- 最少8个字符
- 包含以下3-4项
- 大写字母
- 小写字母
- 数字
- 符号
加分项目 | 算法 |
密码长度 | +(n*4) |
大写字母个数 | +((len-n)*2) |
小写字母个数 | +((len-n)*2) |
数字个数 | +(n*4) |
符号个数 | +(n*6) |
中间数字或符号个数 | +(n*2) |
是否满足要求 | +(n*2) |
减分项目 | 算法 |
只有字母 | -n |
只有数字 | -n |
重复的字符(忽略大小写) | 算法未知,详情见代码 |
连续出现大写字母 | -(n*2) |
连续出现小写字母 | -(n*2) |
连续出现数字 | -(n*2) |
大于3个的按顺序出现的大写字母, 如:ABCD(n从第3个字母开始计数) | -(n*3) |
大于3个的按顺序出现的小写字母(n从第3个字母开始计数) | -(n*3) |
大于3个的按顺序出现的数字(n从第3个字母开始计数) | -(n*3) |
- JavaScript代码
/*
* @Descripttion:
* @version: 0.0.1
* @Author: ZHJI
* @Date: 2019-09-25 11:34:00
* @LastEditors: ZHJI
* @LastEditTime: 2019-09-25 13:23:14
*/
console.log(chkPass("h5(6^u6Ch%4A2v0"))
function chkPass(password) {
if (!password) {
return -1
}
if (password.indexOf(' ') !== -1) {
return -1
}
this.passwordLength = password.length
this.lowerLetterCount = 0
this.upperLetterCount = 0
this.numberLetterCount = 0
this.charLetterCount = 0
let a =getPwdLowerLetterScore(password)
let b =getPwdUpperLetterScore(password)
let c =getPwdLengthScore(password)
let d =getPwdNumberLetterScore(password)
let e =getPwdCharLetterScore()
let f =getPwdNumberOrCharInPasswordScore(password)
let g =getPwdLowRequireScore(password)
let h =getPwdOnlyEnglishLetterScore(password)
let i =getPwdOnlyNumberLetterScore(password)
let j =getPwdRepeatedLetterScore(password)
let k =getPwdContinuouUpperLetterScore(password)
let l =getPwdContinuouLowerLetterScore(password)
let m =getPwdContinuouLowerNumberScore(password)
let n =getPwdContinuouLetterScore(password)
let o =getPwdContinuouNumberScore(password)
let p =getPwdContinuouChartScore(password)
console.log('小写字母得分:' + a)
console.log('大写字母得分:' + b)
console.log('密码长度的得分:' + c)
console.log('数字得分:' + d)
console.log('符号得分:' + e)
console.log(' 中间穿插数字或符号:' + f)
console.log('最低要求得分:' + g)
console.log('仅仅包含字母:' + h)
console.log('仅仅包含数字:' + i)
console.log('重复字符:' + j)
console.log('连续大写字母:' + k)
console.log('连续小写字母:' + l)
console.log('连续数:' + m)
console.log('连续字母 (3):' + n)
console.log('连续数字(3):' + o)
console.log('连续符号(3):' + p)
return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p
/**
* 获取密码长度得分
* @param {String} password
*/
function getPwdLengthScore(password) {
return 4 * this.passwordLength
}
/**
* 获取小写字母得分
* @param {String} password
*/
function getPwdLowerLetterScore(password) {
var lowerLetterCount = 0
for (let i = 0; i < this.passwordLength; i++) {
if (password.charCodeAt(i) >= 'a'.charCodeAt(0) && password.charCodeAt(i) <= 'z'.charCodeAt(0)) {
lowerLetterCount++
}
}
this.lowerLetterCount = lowerLetterCount
if (lowerLetterCount > 0) {
return (this.passwordLength - lowerLetterCount) * 2
} else {
return 0
}
}
/**
* 获取大写字母得分
* @param {String} password
*/
function getPwdUpperLetterScore(password) {
var upperLetterCount = 0
for (let i = 0; i < this.passwordLength; i++) {
if (password.charCodeAt(i) >= 'A'.charCodeAt(0) && password.charCodeAt(i) <= 'Z'.charCodeAt(0)) {
upperLetterCount++
}
}
this.upperLetterCount = upperLetterCount
if (upperLetterCount > 0) {
return (this.passwordLength - upperLetterCount) * 2
} else {
return 0
}
}
/**
* 获取数字得分
* @param {String } password
*/
function getPwdNumberLetterScore(password) {
let numberLetterCount = 0
for (let i = 0; i < this.passwordLength; i++) {
if (password.charCodeAt(i) >= '0'.charCodeAt(0) && password.charCodeAt(i) <= '9'.charCodeAt(0) ){
numberLetterCount++
}
}
this.numberLetterCount = numberLetterCount
return this.passwordLength === numberLetterCount ? 0 : numberLetterCount * 4
}
/**
* 获取符号得分
*/
function getPwdCharLetterScore() {
this.charLetterCount = this.passwordLength - this.lowerLetterCount - this.upperLetterCount - this.numberLetterCount
return this.charLetterCount * 6
}
/**
* 密码中间穿插数字或符号
* @param {String} password
*/
function getPwdNumberOrCharInPasswordScore(password) {
var result = this.numberLetterCount + this.charLetterCount
if (!(
(password.charCodeAt(0) >= 'A'.charCodeAt(0) && password.charCodeAt(0) <= 'Z'.charCodeAt(0) )
||
(password.charCodeAt(0) >= 'a'.charCodeAt(0) && password.charCodeAt(0) <= 'z'.charCodeAt(0))
) ){
result--
}
if (!(
(password.charCodeAt(this.passwordLength - 1) >= 'A'.charCodeAt(0) && password.charCodeAt(this.passwordLength - 1) <= 'Z'.charCodeAt(0))
||
(password.charCodeAt(this.passwordLength - 1) >= 'a'.charCodeAt(0) && password.charCodeAt(this.passwordLength - 1) <= 'z'.charCodeAt(0))
) ){
result--
}
return result * 2
}
/**
* 获取最低要求得分
* @param {*} password
*/
function getPwdLowRequireScore(password) {
var result = 0
if (this.passwordLength >= 8) {
result++
}
if (this.upperLetterCount > 0) {
result++
}
if (this.lowerLetterCount > 0) {
result++
}
if (this.numberLetterCount > 0) {
result++
}
if (this.charLetterCount > 0) {
result++
}
// 长度没有8位或者3项条件没有满足3个以上 直接返回0
if (this.passwordLength < 8 || result < 4) {
return 0
} else {
return result * 2
}
}
/**
* 仅仅包含字母
* @param {String} password
*/
function getPwdOnlyEnglishLetterScore(password) {
return this.passwordLength === this.lowerLetterCount + this.upperLetterCount ? -this.passwordLength : 0
}
/**
* 仅仅包含数字
* @param {String } password
*/
function getPwdOnlyNumberLetterScore(password) {
return this.passwordLength === this.numberLetterCount ? -this.passwordLength : 0
}
/**
* 重复字符
* @param {String} password
*/
function getPwdRepeatedLetterScore(password) {
var nRepChar = 0
var nUnqChar = 0
var nRepInc = 0
var arrPwd = password.replace('\s+', '').split('')
var arrPwdLen = arrPwd.length
for (let a = 0; a < arrPwdLen; a++) {
var bCharExists = false
for (let b = 0; b < arrPwdLen; b++) {
if (arrPwd[a]===arrPwd[b] && a !== b) { /* repeat character exists */
bCharExists = true
nRepInc += Math.abs(arrPwdLen / (b - a))
}
}
if (bCharExists) {
nRepChar++
nUnqChar = arrPwdLen - nRepChar
nRepInc = ((nUnqChar !== 0) ? Math.ceil(nRepInc / nUnqChar) : Math.ceil(nRepInc))
}
}
return -nRepInc
}
/**
* 连续大写字母
* @param {String } password
*/
function getPwdContinuouUpperLetterScore(password) {
var j = 0
for (let i = 0; i < password.length - 1; i++) {
if (password.charCodeAt(i) >= 'A'.charCodeAt(0) && password.charCodeAt(i) <= 'Z'.charCodeAt(0) ){
if (password.charCodeAt(i + 1) >= 'A'.charCodeAt(0) && password.charCodeAt(i + 1) <= 'Z'.charCodeAt(0)) {
j++
}
}
}
return -2 * j
}
/**
* 连续小写字母
* @param {String} password
*/
function getPwdContinuouLowerLetterScore(password) {
var j = 0
for (let i = 0; i < password.length - 1; i++) {
if (password.charCodeAt(i) >= 'a'.charCodeAt(0) && password.charCodeAt(i) <= 'z'.charCodeAt(0)) {
if (password.charCodeAt(i + 1) >= 'a'.charCodeAt(0) && password.charCodeAt(i + 1) <= 'z'.charCodeAt(0)) {
j++
}
}
}
return -2 * j
}
/**
* 连续数
* @param {String} password
*/
function getPwdContinuouLowerNumberScore(password) {
var j = 0
for (let i = 0; i < password.length - 1; i++) {
if (password.charCodeAt(i) >= '0'.charCodeAt(0) && password.charCodeAt(i) <= '9'.charCodeAt(0) ){
if (password.charCodeAt(i + 1) >= '0'.charCodeAt(0) && password.charCodeAt(i + 1) <= '9'.charCodeAt(0) ) {
j++
}
}
}
return -2 * j
}
/**
* 连续字母 3+ (like abc)
* @param {String} password
*/
function getPwdContinuouLetterScore(password) {
password = password.toUpperCase()
var j = 0
for (var i = 0; i < password.length - 2; i++) {
if (password.charCodeAt(i) >= 'A'.charCodeAt(0) && password.charCodeAt(i) <= 'Z'.charCodeAt(0)) {
if ((password.charCodeAt(i + 1) === password.charCodeAt(i) + 1) && (password.charCodeAt(i + 2) === password.charCodeAt(i) + 2)) {
j++
}
if ((password.charCodeAt(i + 1) === password.charCodeAt(i) - 1) && (password.charCodeAt(i + 2) === password.charCodeAt(i) - 2)) {
j++
}
}
}
return -3 * j
}
/**
* 连续数字 3+ (like 123)
* @param {String } password
*/
function getPwdContinuouNumberScore(password) {
var j = 0
for (var i = 0; i < password.length - 2; i++) {
if (password.charCodeAt(i) >= '0'.charCodeAt(0) && password.charCodeAt(i) <= '9'.charCodeAt(0) ) {
if ((password.charCodeAt(i + 1) === password.charCodeAt(i) + 1) && (password.charCodeAt(i + 2) === password.charCodeAt(i) + 2)) {
j++
}
if ((password.charCodeAt(i + 1) === password.charCodeAt(i) - 1) && (password.charCodeAt(i + 2) === password.charCodeAt(i) - 2)) {
j++
}
}
}
return -3 * j
}
/**
* 连续符号 3+ (like !@#)
* @param {String} password
*/
function getPwdContinuouChartScore(password) {
var nSeqSymbol = 0
var dict = ')!@#$%^&*()'
for (let s = 0; s < 8; s++) {
var sFwd = dict.substring(s, s + 3)
if (password.indexOf(sFwd) !== -1 || password.split("").reverse().join("").indexOf(sFwd) != -1) {
nSeqSymbol++
}
}
return -3 * nSeqSymbol
}
}
- java代码片段
package Tool;
import java.util.Locale;
import java.util.regex.Pattern;
/**
*
* @author ZHJI
*
*/
public class Main {
private int passwordLength = 0;
private int lowerLetterCount =0;
private int upperLetterCount =0;
private int numberLetterCount =0;
private int charLetterCount =0;
public static void main(String[] args) throws Exception {
Main testMain = new Main();
System.out.println(testMain.chkPass("test123456"));
}
public int chkPass(String password){
if (password != null && !password.isEmpty()) {
this.passwordLength = password.length();
int a = this.getPwdLowerLetterScore(password);
int b = this.getPwdUpperLetterScore(password);
int c = this.getPwdLengthScore(password);
int d = this.getPwdNumberLetterScore(password);
int e = this.getPwdCharLetterScore();
int f = this.getPwdNumberOrCharInPasswordScore(password);
int g = this.getPwdLowRequireScore(password);
int h = this.getPwdOnlyEnglishLetterScore(password);
int i = this.getPwdOnlyNumberLetterScore(password);
int j = this.getPwdRepeatedLetterScore(password);
int k = this.getPwdContinuouUpperLetterScore(password);
int l = this.getPwdContinuouLowerLetterScore(password);
int m = this.getPwdContinuouLowerNumberScore(password);
int n = this.getPwdContinuouLetterScore(password);
int o = this.getPwdContinuouNumberScore(password);
int p = this.getPwdContinuouChartScore(password);
System.out.println("小写字母得分:" +a);
System.out.println("大写字母得分:" + b);
System.out.println("密码长度的得分:" +c);
System.out.println("数字得分:" + d);
System.out.println("符号得分:" + e);
System.out.println(" 中间穿插数字或符号:" +f );
System.out.println("最低要求得分:" +g);
System.out.println("仅仅包含字母:" +h );
System.out.println("仅仅包含数字:" +i );
System.out.println("重复字符:" +j );
System.out.println("连续大写字母:" +k );
System.out.println("连续小写字母:" +l );
System.out.println("连续数:" + m);
System.out.println("连续字母 (3):" + n);
System.out.println("连续数字(3):" +o );
System.out.println("连续符号(3):" +p );
return a+b+c+d+e+f+g+h+i+j+k+l+m+n+o+p;
}else {
System.out.println("传入密码不合法" + password);
return 0;
}
}
/*
* <i>获取密码长度的得分</i>
*/
private int getPwdLengthScore(String password) {
return 4*this.passwordLength;
}
/*
* <i>获取小写字母得分</i>
*/
private int getPwdLowerLetterScore(String password) {
int lowerLetterCount = 0;
for(int i=0;i<this.passwordLength;i++){
if (password.charAt(i)>='a' && password.charAt(i)<='z' ) {
lowerLetterCount++;
}
}
this.lowerLetterCount = lowerLetterCount;
if (lowerLetterCount>0) {
return (this.passwordLength - lowerLetterCount)*2;
}else {
return 0;
}
}
/*
* <i>获取大写字母得分</i>
*/
private int getPwdUpperLetterScore(String password) {
int upperLetterCount = 0;
for(int i=0;i<this.passwordLength;i++){
if (password.charAt(i)>='A' && password.charAt(i)<='Z' ) {
upperLetterCount++;
}
}
this.upperLetterCount = upperLetterCount;
if (upperLetterCount>0) {
return (this.passwordLength - upperLetterCount)*2;
}else {
return 0;
}
}
/*
* <i>获取数字得分</i>
*/
private int getPwdNumberLetterScore(String password) {
int numberLetterCount = 0;
for(int i=0;i<this.passwordLength;i++){
if (password.charAt(i)>='0' && password.charAt(i)<='9' ) {
numberLetterCount++;
}
}
this.numberLetterCount = numberLetterCount;
return this.passwordLength == numberLetterCount?0:numberLetterCount*4;
}
/*
* <i>获取符号得分</i>
*/
private int getPwdCharLetterScore() {
this.charLetterCount = this.passwordLength - this.lowerLetterCount - this.upperLetterCount - this.numberLetterCount;
return this.charLetterCount*6;
}
/*
* <i>密码中间穿插数字或符号</i>
*/
private int getPwdNumberOrCharInPasswordScore(String password) {
int result = this.numberLetterCount+this.charLetterCount;
if (!((password.charAt(0)>='A' && password.charAt(0)<='Z')|| (password.charAt(0)>='a' && password.charAt(0)<='z'))) {
result--;
}
if (!((password.charAt(this.passwordLength-1)>='A' && password.charAt(this.passwordLength-1)<='Z')|| (password.charAt(this.passwordLength-1)>='a' && password.charAt(this.passwordLength-1)<='z'))) {
result--;
}
return result*2;
}
/*
* <i>最低要求得分</i>
*/
private int getPwdLowRequireScore(String password) {
int result = 0;
if (this.passwordLength>=8) {
result++;
}
if (this.upperLetterCount>0) {
result++;
}
if (this.lowerLetterCount>0) {
result++;
}
if (this.numberLetterCount>0) {
result++;
}
if (this.charLetterCount>0) {
result++;
}
// 长度没有8位或者3项条件没有满足3个以上 直接返回0
if (this.passwordLength<8 || result<4) {
return 0;
}else {
return result*2;
}
}
/*
* <i>仅仅包含字母</i>
*/
private int getPwdOnlyEnglishLetterScore(String password) {
return this.passwordLength == this.lowerLetterCount + this.upperLetterCount?-this.passwordLength:0;
}
/*
* <i>仅仅包含数字</i>
*/
private int getPwdOnlyNumberLetterScore(String password) {
return this.passwordLength == this.numberLetterCount ?-this.passwordLength:0;
}
/*
* <i>重复字符 </i>
*/
private int getPwdRepeatedLetterScore(String password) {
int nRepChar=0,nUnqChar=0;
double nRepInc=0;
String[] arrPwd = password.replace("\\s+","").split("\\s*");
int arrPwdLen = arrPwd.length;
for (int a=0; a < arrPwdLen; a++) {
boolean bCharExists = false;
for (int b=0; b < arrPwdLen; b++) {
if (arrPwd[a].equals(arrPwd[b]) && a != b) { /* repeat character exists */
bCharExists = true;
nRepInc += Math.abs(arrPwdLen/(double)(b-a));
}
}
if (bCharExists) {
nRepChar++;
nUnqChar = arrPwdLen-nRepChar;
nRepInc = ((nUnqChar!=0) ? Math.ceil(nRepInc/nUnqChar) : Math.ceil(nRepInc));
}
}
return -(int)nRepInc;
}
/*
* <i>连续大写字母 </i>
*/
private int getPwdContinuouUpperLetterScore(String password) {
int j=0;
char[] c = password.toCharArray();
for (int i = 0; i < c.length-1; i++) {
if(Pattern.compile("[A-Z]").matcher(c[i]+"").find()){
if (Pattern.compile("[A-Z]").matcher(c[i+1]+"").find()) {
j++;
}
}
}
return -2*j;
}
/*
* <i>连续小写字母 </i>
*/
private int getPwdContinuouLowerLetterScore(String password) {
int j=0;
char[] c = password.toCharArray();
for (int i = 0; i < c.length-1; i++) {
if(Pattern.compile("[a-z]").matcher(c[i]+"").find()){
if (Pattern.compile("[a-z]").matcher(c[i+1]+"").find()) {
j++;
}
}
}
return -2*j;
}
/*
* <i>连续数 </i>
*/
private int getPwdContinuouLowerNumberScore(String password) {
int j=0;
char[] c = password.toCharArray();
for (int i = 0; i < c.length-1; i++) {
if(Pattern.compile("[0-9]").matcher(c[i]+"").find()){
if (Pattern.compile("[0-9]").matcher(c[i+1]+"").find()) {
j++;
}
}
}
return -2*j;
}
public int getPwdContinuouLetterScore(String password){
int j=0;
char[] c = password.toLowerCase(Locale.CHINA).toCharArray();
for (int i = 0; i < c.length-2; i++) {
if (Pattern.compile("[a-z]").matcher(c[i]+"").find()) {
if ((c[i+1]==c[i]+1) && (c[i+2]==c[i]+2)) {
j++;
}
if ((c[i+1]==c[i]-1) && (c[i+2]==c[i]-2)) {
j++;
}
}
}
return -3*j;
}
public int getPwdContinuouNumberScore(String password){
int j=0;
char[] c = password.toLowerCase(Locale.CHINA).toCharArray();
for (int i = 0; i < c.length-2; i++) {
if (Pattern.compile("[0-9]").matcher(c[i]+"").find()) {
if ((c[i+1]==c[i]+1) && (c[i+2]==c[i]+2)) {
j++;
}
if ((c[i+1]==c[i]-1) && (c[i+2]==c[i]-2)) {
j++;
}
}
}
return -3*j;
}
public int getPwdContinuouChartScore(String password){
int nSeqSymbol = 0;
String dict = ")!@#$%^&*()";
for (int s=0; s < 8; s++) {
String sFwd = dict.substring(s,s+3);
if (password.indexOf(sFwd) != -1 || new StringBuilder(password).reverse().toString().indexOf(sFwd) != -1) {
nSeqSymbol++;
}
}
return -3*nSeqSymbol;
}
}
- 最后更新时间:2019/09/25 16:23