算法-如何有效评估用户输入的密码的强度?
看到网上很多应用在创建或者修改密码时都会动态提示用户当前输入的密码的强度,他们是根据什么原理来评估的呢?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
看到网上很多应用在创建或者修改密码时都会动态提示用户当前输入的密码的强度,他们是根据什么原理来评估的呢?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(7)
我觉得首先是根据各种密保方式,给每种密保方式赋于一个权值,然后根据这个帐号的具体情况,计算所有权值总和,达到多少多少的标准即为强,多少为弱,诸如此类。
我觉得至少需要一个简单正则表达式去检验吧。
比如abcd....z012..9 虽然够长,但是字符串有规律,容易被程序“猜出”。
这样的检测一般都是通过检测密码的各类字符的组合规则,常见的强度规则如下:
1) 任何少于6个字符的组合,弱;任何字符数的同类字符组合,弱;
2) 任何字符数的两类字符组合,中;
3) 12位字符数以下的三类或四类字符组合,强;
4) 12位字符数以上的三类或四类字符组合,非常好。
以下提供测试的强度检测HTML代码和JavaScript代码,以供参考:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>密码强度检测</title>
<style type="text/css">
body{font:12px/1.5 Arial;}
input{float:left;font-size:12px;width:150px;font-family:arial;border:1px solid #ccc;padding:3px;}
input.correct{border:1px solid green;}
input.error{border:1px solid red;}
#tips{float:left;margin:2px 0 0 20px;}
#tips span{float:left;width:50px;height:20px;color:#fff;overflow:hidden;background:#ccc;margin-right:2px;line-height:20px;text-align:center;}
#tips.s1 .active{background:#f30;}
#tips.s2 .active{background:#fc0;}
#tips.s3 .active{background:#cc0;}
#tips.s4 .active{background:#090;}
</style>
<script type="text/javascript">
window.onload = function ()
{
var oTips = document.getElementById("tips");
var oInput = document.getElementsByTagName("input")[0];
var aSpan = oTips.getElementsByTagName("span");
var aStr = ["弱", "中", "强", "非常好"];
var i = 0;
oInput.onkeyup = oInput.onfocus = oInput.onblur = function ()
{
var index = checkStrong(this.value);
this.className = index ? "correct" : "error";
oTips.className = "s" + index;
for (i = 0; i < aSpan.length; i++)aSpan[i].className = aSpan[i].innerHTML = "";
index && (aSpan[index - 1].className = "active", aSpan[index - 1].innerHTML = aStr[index - 1])
}
};
/** 强度规则
+ ------------------------------------------------------- +
1) 任何少于6个字符的组合,弱;任何字符数的同类字符组合,弱;
2) 任何字符数的两类字符组合,中;
3) 12位字符数以下的三类或四类字符组合,强;
4) 12位字符数以上的三类或四类字符组合,非常好。
+ ------------------------------------------------------- +
**/
//检测密码强度
function checkStrong(sValue)
{
var modes = 0;
if (sValue.length < 6) return modes;
if (/d/.test(sValue)) modes++; //数字
if (/[a-z]/.test(sValue)) modes++; //小写
if (/[A-Z]/.test(sValue)) modes++; //大写
if (/W/.test(sValue)) modes++; //特殊字符
switch (modes)
{
case 1:
return 1;
break;
case 2:
return 2;
case 3:
case 4:
return sValue.length < 12 ? 3 : 4
break;
}
}
</script>
</head>
<body>
<input type="password" value="" maxlength="16" />
<div id="tips"><span></span><span></span><span></span><span></span></div>
</body>
</html>
密码强度评判标准相信都大同小异,只是实现上会做些许取舍。这里提供一种jQuery的解决方案,仅供参考。
jQuery插件password_plugin.js的代码如下:
(function($){
$.fn.shortPass = 'Too short';
$.fn.badPass = 'Weak';
$.fn.goodPass = 'Good';
$.fn.strongPass = 'Strong';
$.fn.samePassword = 'Username and Password identical.';
$.fn.resultStyle = "";
$.fn.passStrength = function(options) {
var defaults = {
shortPass: "shortPass", //optional
badPass: "badPass", //optional
goodPass: "goodPass", //optional
strongPass: "strongPass", //optional
baseStyle: "testresult", //optional
userid: "", //required override
messageloc: 1 //before == 0 or after == 1
};
var opts = $.extend(defaults, options);
return this.each(function() {
var obj = $(this);
$(obj).unbind().keyup(function()
{
var results = $.fn.teststrength($(this).val(),$(opts.userid).val(),opts);
if(opts.messageloc === 1)
{
$(this).next("." + opts.baseStyle).remove();
$(this).after("<span class=""+opts.baseStyle+""><span></span></span>");
$(this).next("." + opts.baseStyle).addClass($(this).resultStyle).find("span").text(results);
}
else
{
$(this).prev("." + opts.baseStyle).remove();
$(this).before("<span class=""+opts.baseStyle+""><span></span></span>");
$(this).prev("." + opts.baseStyle).addClass($(this).resultStyle).find("span").text(results);
}
});
//FUNCTIONS
$.fn.teststrength = function(password,username,option){
var score = 0;
//password < 4
if (password.length < 4 ) { this.resultStyle = option.shortPass;return $(this).shortPass; }
//password == user name
if (password.toLowerCase()==username.toLowerCase()){this.resultStyle = option.badPass;return $(this).samePassword;}
//password length
score += password.length * 4;
score += ( $.fn.checkRepetition(1,password).length - password.length ) * 1;
score += ( $.fn.checkRepetition(2,password).length - password.length ) * 1;
score += ( $.fn.checkRepetition(3,password).length - password.length ) * 1;
score += ( $.fn.checkRepetition(4,password).length - password.length ) * 1;
//password has 3 numbers
if (password.match(/(.*[0-9].*[0-9].*[0-9])/)){ score += 5;}
//password has 2 symbols
if (password.match(/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/)){ score += 5 ;}
//password has Upper and Lower chars
if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/)){ score += 10;}
//password has number and chars
if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/)){ score += 15;}
//
//password has number and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/)){ score += 15;}
//password has char and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/)){score += 15;}
//password is just a numbers or chars
if (password.match(/^w+$/) || password.match(/^d+$/) ){ score -= 10;}
//verifying 0 < score < 100
if ( score < 0 ){score = 0;}
if ( score > 100 ){ score = 100;}
if (score < 34 ){ this.resultStyle = option.badPass; return $(this).badPass;}
if (score < 68 ){ this.resultStyle = option.goodPass;return $(this).goodPass;}
this.resultStyle= option.strongPass;
return $(this).strongPass;
};
});
};
})(jQuery);
$.fn.checkRepetition = function(pLen,str) {
var res = "";
for (var i=0; i<str.length ; i++ )
{
var repeated=true;
for (var j=0;j < pLen && (j+i+pLen) < str.length;j++){
repeated=repeated && (str.charAt(j+i)==str.charAt(j+i+pLen));
}
if (j<pLen){repeated=false;}
if (repeated) {
i+=pLen-1;
repeated=false;
}
else {
res+=str.charAt(i);
}
}
return res;
};
使用时需要和jQuery一起包含进去。
用到的css文件:
td label{
font-size:14px;
font-weight:bold;
color:#666;
font-family: arail,helvetica,san-serif;
}
input{
height:28px;
width:200px;
border:1px solid #ccc;
font-size:16px;
font-weight: bold;
color:#666;
padding:7px 0 0 4px;
}
/* ADVANCED STYLES */
.top_testresult{
font-weight: bold;
font-size:13px;
font-family: arail,helvetica,san-serif;
color:#666;
padding:0;
margin:0 0 2px 0;
}
.top_testresult span{
padding:6px ;
margin:0;
}
.top_shortPass{
background:#edabab;
border:1px solid #bc0000;
display:block;
}
.top_shortPass span{
}
.top_badPass{
background:#edabab;
border:1px solid #bc0000;
display:block;
}
.top_badPass span{
}
.top_goodPass{
background:#ede3ab;
border:1px solid #bc9f00;
display:block;
}
.top_goodPass span{
}
.top_strongPass{
background:#d3edab;
border:1px solid #73bc00;
display:block;
}
.top_strongPass span{
}
/* RESULT STYLE */
.testresult{
font-weight: bold;
font-size:13px;
font-family: arial,helvetica,san-serif;
color:#666;
padding:0px 0px 12px 10px;
margin-left:10px;
display: block;
height:28px;
float:left;
}
.testresult span{
padding:10px 20px 12px 10px;
margin: 0px 0px 0px 20px;
display:block;
float:right;
white-space: nowrap;
}
.shortPass{
background:url(../images/red.png) no-repeat 0 0;
}
.shortPass span{
background:url(../images/red.png) no-repeat top right;
}
.badPass{
background:url(../images/red.png) no-repeat 0 0;
}
.badPass span{
background:url(../images/red.png) no-repeat top right;
}
.goodPass{
background:url(../images/yellow.png) no-repeat 0 0;
}
.goodPass span{
background:url(../images/yellow.png) no-repeat top right;
}
.strongPass{
background:url(../images/green.png) no-repeat 0 0;
}
.strongPass span{
background:url(../images/green.png) no-repeat top right;
}
使用举例:
<title>无标题页</title>
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
<!-- custom select plugin js -->
<script type="text/javascript" src="js/password_plugin.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script>
$(document).ready( function() {
//BASIC
$(".password_test").passStrength({
userid: "#user_id"
});
//ADVANCED
$(".password_adv").passStrength({
shortPass: "top_shortPass",
badPass: "top_badPass",
goodPass: "top_goodPass",
strongPass: "top_strongPass",
baseStyle: "top_testresult",
userid: "#user_id_adv",
messageloc: 0
});
});
</script>
<body>
<table cellpadding="2" cellspacing="0" border="0">
<tr>
<td align="right"><label>User Name:</label></td>
<td><input type="text" name="user_name" id="user_id_adv"/></td>
</tr>
<tr>
<td align="right"><label>Password:</label></td>
<td><input type="password" name="pass_word" class="password_adv"/></td>
</tr>
</table>
</body>
效果图:
一个高强度的密码,应该要符合以下几个原则:
长度。
不是单一的(如纯数字、纯字母)。
大小写混合。
特殊字符。(这一点可以做保留意见)
根据这几种原则就可以比较方便的写出相应的检测代码。
如果是网页前段可以通过JS实现,实现方式比较简单基本原则就是:
1.如果密码少于5位,那么就认为这是一个弱密码。
2.如果密码只由数字、小写字母、大写字母或其它特殊符号当中的一种组成,则认为这是一个弱密码。
3.如果密码由数字、小写字母、大写字母或其它特殊符号当中的两种组成,则认为这是一个中度安全的密码。
4.如果密码由数字、小写字母、大写字母或其它特殊符号当中的三种以上组成,则认为这是一个比较安全的密码。
实例代码:
<script language=java script>
//CharMode函数
// 测试某个字符是属于哪一类.
function CharMode(iN){
if (iN>=48 && amp; iN <=57) //数字
return 1;
if (iN>=65 && iN & lt;=90) //大写字母
return 2;
if (iN>=97 && iN & lt;=122) //小写
return 4;
else
return 8; //特殊字符
}
//bitTotal 函数
//计算出当前密码当中一共有多少种模式
function bitTotal(num){
modes=0;
for (i=0;i<4;i++){
if (num & 1) modes++;
num>>>=1;
}
return modes;
}
//checkStrong函数
//返回密码的强度级别
function checkStrong(sPW){
if (sPW.length<=4)
return 0; //密码太短
Modes=0;
for (i=0;i<sPW.length;i++){
//测试每一个字符的类别并统计一共有多少种模式.
Modes|=CharMode(sPW.charCodeAt(i));
}
return bitTotal(Modes);
}
//pwStrength函数
// 当用户放开键盘或密码输入框失去焦点时,根据不同的级别显示不同的颜色
function pwStrength(pwd){
O_color="#eeeeee";
L_color="#FF0000";
M_color="#FF9900";
H_color="#33CC00";
if (pwd==null||pwd==''){
Lcolor=Mcolor=Hcolor=O_color;
}
else{
S_level=checkStrong(pwd);
switch(S_level) {
case 0:
Lcolor=Mcolor=Hcolor=O_color;
case 1:
Lcolor=L_color;
Mcolor=Hcolor=O_color;
break;
case 2:
Lcolor=Mcolor=M_color;
Hcolor=O_color;
break;
default:
Lcolor=Mcolor=Hcolor=H_color;
}
}
document.getElementById("strength_L").style.background=Lcolor;
document.getElementById("strength_M").style.background=Mcolor;
document.getElementById("strength_H").style.background=Hcolor;
return;
}
</script>
<form name=form1 action="" >
输入密码:<input TYPE=password DEFAULT CHARSET=gbk size=10 onKeyUp=pwStrength(this.value) onBlur=pwStrength(this.value)>
<br>密码强度:
<table width="217" border="1" cellspacing="0" cellpadding="1" bordercolor="#cccccc" height="23" style='display:inline'>
<tr align="center" bgcolor="#eeeeee">
<td width="33%" id="strength_L"& gt;弱</td>
<td width="33%" id="strength_M">中</td& gt;
<td width="33%" id="strength_H">强</td>
</tr>
</table>
</form>
老外写的一个比较全的密码判断,我一直有用,分享一下。
样式的地方使用时自己结合实际情况修改
<html>
<head>
<script type="text/javascript">
var m_strUpperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var m_strLowerCase = "abcdefghijklmnopqrstuvwxyz";
var m_strNumber = "0123456789";
var m_strCharacters = "!@#$%^&*?_~"
function checkPassword(strPassword)
{
var nScore = 0;
if (strPassword.length < 5)
{
nScore += 5;
}
else if (strPassword.length > 4 && strPassword.length < 8)
{
nScore += 10;
}
else if (strPassword.length > 7)
{
nScore += 25;
}
var nUpperCount = countContain(strPassword, m_strUpperCase);
var nLowerCount = countContain(strPassword, m_strLowerCase);
var nLowerUpperCount = nUpperCount + nLowerCount;
if (nUpperCount == 0 && nLowerCount != 0)
{
nScore += 10;
}
else if (nUpperCount != 0 && nLowerCount != 0)
{
nScore += 20;
}
var nNumberCount = countContain(strPassword, m_strNumber);
if (nNumberCount == 1)
{
nScore += 10;
}
if (nNumberCount >= 3)
{
nScore += 20;
}
var nCharacterCount = countContain(strPassword, m_strCharacters);
if (nCharacterCount == 1)
{
nScore += 10;
}
if (nCharacterCount > 1)
{
nScore += 25;
}
if (nNumberCount != 0 && nLowerUpperCount != 0)
{
nScore += 2;
}
if (nNumberCount != 0 && nLowerUpperCount != 0 && nCharacterCount != 0)
{
nScore += 3;
}
if (nNumberCount != 0 && nUpperCount != 0 && nLowerCount != 0 && nCharacterCount != 0)
{
nScore += 5;
}
return nScore;
}
function runPassword(strPassword, strFieldID)
{
var nScore = checkPassword(strPassword);
var ctlBar = document.getElementById(strFieldID + "_bar");
var ctlText = document.getElementById(strFieldID + "_text");
if (!ctlBar || !ctlText)
return;
ctlBar.style.width = (nScore*1.25>100)?100:nScore*1.25 + "%";
if (nScore >= 80)
{
var strText = "Very Strong";
var strColor = "#008000";
}
else if (nScore >= 60)
{
var strText = "Strong";
var strColor = "#006000";
}
else if (nScore >= 40)
{
var strText = "Average";
var strColor = "#e3cb00";
}
else if (nScore >= 20)
{
var strText = "Weak";
var strColor = "#Fe3d1a";
}
else
{
var strText = "Very Weak";
var strColor = "#e71a1a";
}
console.log(strText);
if(strPassword.length == 0)
{
ctlBar.style.backgroundColor = "";
ctlText.innerHTML = "";
}
else
{
ctlBar.style.backgroundColor = strColor;
ctlText.innerHTML = strText;
}
}
function countContain(strPassword, strCheck)
{
var nCount = 0;
for (i = 0; i < strPassword.length; i++)
{
if (strCheck.indexOf(strPassword.charAt(i)) > -1)
{
nCount++;
}
}
return nCount;
}
</script>
</head>
<body>
<input type="password" id="passwd" value="" onkeyup="runPassword(this.value, 'process');"/> <br />
<div id="process_bar" style="width:50px; height:25px"></div><span id="process_text"></span>
</body>
</html>