Rich Rumble
asked on
javascript to enforce password complexity
I'm doing a demonstration for Security Awareness Training, and I want a web-form that users can visit on the internal intranet and see if their password will be rejected or weak.
I found a js-fiddle that has some good regex, but I'd like to expand that to also include a routine that looks for words as well.
http://jsfiddle.net/aleem/KE3RB/8/ <--This is pretty good as far as the main complexity of our companies settings, 99% of the passwords I put in, and that match "STRONG" are passwords we can use. I'd like to have one final check, look for the top 500 most common passwords as well.
https://wiki.skullsecurity.org/images/c/ca/500-worst-passwords.txt
I'd like the passwords in an csv or array inside the JS rather than calling the list from an external site. I clearly don't know enough about JS to mange this myself. Can anyone help me with adding in another check for that list of words?
Thanks!
-rich
I found a js-fiddle that has some good regex, but I'd like to expand that to also include a routine that looks for words as well.
http://jsfiddle.net/aleem/KE3RB/8/ <--This is pretty good as far as the main complexity of our companies settings, 99% of the passwords I put in, and that match "STRONG" are passwords we can use. I'd like to have one final check, look for the top 500 most common passwords as well.
https://wiki.skullsecurity.org/images/c/ca/500-worst-passwords.txt
I'd like the passwords in an csv or array inside the JS rather than calling the list from an external site. I clearly don't know enough about JS to mange this myself. Can anyone help me with adding in another check for that list of words?
Thanks!
-rich
ASKER
Super close, I'd like it to be more "grep like", should it find even one of those words, rate it as weak-common-word.
I tried these, both I'd like to be disqualified because they contain "password" in them.
password1234A! (says strong, but I'd like it as weak)
Password1234! (says strong, but I'd like it as weak)
Capital "P" in password threw it off from the start, should probably be case insensitive.
Others I'd like it to disqualify because of a word (weak-common-word)
123PaSSword!
!!passWORD2
Is that possible? Thanks again, this should be exactly what I need when it can disqualify passes like those!
-rich
I tried these, both I'd like to be disqualified because they contain "password" in them.
password1234A! (says strong, but I'd like it as weak)
Password1234! (says strong, but I'd like it as weak)
Capital "P" in password threw it off from the start, should probably be case insensitive.
Others I'd like it to disqualify because of a word (weak-common-word)
123PaSSword!
!!passWORD2
Is that possible? Thanks again, this should be exactly what I need when it can disqualify passes like those!
-rich
Complex, hard-to-remember passwords are still easily cracked and are a hateful anti-pattern. Please don't do that to your clients.
Consider using a pass-phrase instead of a password. Just don't use Correct Horse Battery staple.
https://xkcd.com/936/
You might try this service (you must enable cookies for it to work).
http://correcthorsebatterystaple.net/
For a better understanding of the issues, please search this article for An Afterword: About Storing Passwords.
https://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html
Consider using a pass-phrase instead of a password. Just don't use Correct Horse Battery staple.
https://xkcd.com/936/
You might try this service (you must enable cookies for it to work).
http://correcthorsebatterystaple.net/
For a better understanding of the issues, please search this article for An Afterword: About Storing Passwords.
https://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html
ASKER
Oh I know Ray, I'm the king of passwords :) but we have to do baby steps for the users, this is one such step in their education.
https://www.experts-exchange.com/articles/12386/How-secure-are-passwords.html <--me
-rich
https://www.experts-exchange.com/articles/12386/How-secure-are-passwords.html <--me
-rich
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
That's excellent! I think this is a good step in the right direction for many of the users, thanks for doing this!
I forked the JSFiddle, and changed the ***** box to a normal input for testing
http://jsfiddle.net/xr2xyshs/1/ (change input type hide the input)
-rich
I forked the JSFiddle, and changed the ***** box to a normal input for testing
http://jsfiddle.net/xr2xyshs/1/ (change input type hide the input)
-rich
ASKER
Very good work, thanks!
ASKER
ty!
greetings richrumble, , your last comment about -
"password1234A! (says strong, but I'd like it as weak)"
would be terribly difficult to implement because there are TOO MANY character variations possible, and as far as the "security" considerations for this testing. . . .
My opinion is -
I can NOT see any benefit to it, the dictionary attacks (using common 'bad passwords'), can not use "combination" test attempts like -
password2
or
password1234A!
because a phrase like "password" in the entry characters for a site , does not lower security much, if any, when there are other characters included with that.
Just because a common phrase like "baseball" is a risk in dictionary attacks, when that's all of the characters in the pass phrase, but if just one other character is in the phrase, then the dictionary attack is not effective, since adding just a single character "baseball9" will require a multiplier of 92 tests (the english keyboard has about 92 possible entries), so this will convert it to a modified Bruteforce attack. And if the characters can also be placed before as "9baseball" then the dictionary words as part of string, are no longer a disadvantage in security? ? ?
If you are concerned with javascript detection of security ratings of password entries, I can not see you using such a simplistic test as your -
below is some code you might consider that uses a better calculation formulae for a relative security rating by javascript -
first the HTML -
next the javascript -
"password1234A! (says strong, but I'd like it as weak)"
would be terribly difficult to implement because there are TOO MANY character variations possible, and as far as the "security" considerations for this testing. . . .
My opinion is -
I can NOT see any benefit to it, the dictionary attacks (using common 'bad passwords'), can not use "combination" test attempts like -
password2
or
password1234A!
because a phrase like "password" in the entry characters for a site , does not lower security much, if any, when there are other characters included with that.
Just because a common phrase like "baseball" is a risk in dictionary attacks, when that's all of the characters in the pass phrase, but if just one other character is in the phrase, then the dictionary attack is not effective, since adding just a single character "baseball9" will require a multiplier of 92 tests (the english keyboard has about 92 possible entries), so this will convert it to a modified Bruteforce attack. And if the characters can also be placed before as "9baseball" then the dictionary words as part of string, are no longer a disadvantage in security? ? ?
If you are concerned with javascript detection of security ratings of password entries, I can not see you using such a simplistic test as your -
strongRegex = new RegExp("^(?=.{8,})(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W).*$", "g");
mediumRegex = new RegExp("^(?=.{7,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))).*$", "g");
enoughRegex = new RegExp("(?=.{6,}).*", "g");
below is some code you might consider that uses a better calculation formulae for a relative security rating by javascript -
first the HTML -
<style>
#passCon {
position:relative;
width: 20em;
border: 2px dotted #b0d;
padding:8px;
}
#warn {
position:absolute;
display: none;
top:5px;
left:5px;
background: #dc0;
padding:8px;
border:2px solid #33b;
z-index:2;
}
#info1 {
text-align:center;
text-decoration: italic;
}
#indic {
width:300px;
height:23px;
border:3px solid #a22;
margin: 4px 0;
}
#prog {
width:2px;
height:23px;
background:#d41010;
}
</style>
<div id="passCon">
<div id="warn">You can ass A Calpital letter</div>
<div id="info1">Your password must be at least 8 characters long,<br />and no more than 20 characters in length</div>
Password: <input id="passIn" type="password" name="name" size="20" maxlength="20" value="" onkeyup="checkPass(this.value);" /> - <span id="chk" style="background:red;"> less than 8 </span><br />
<div id="indic"><div id="prog"></div></div>
</div>
next the javascript -
<script>
function id2ob(elmt1){return document.getElementById(elmt1);}
var domPs=id2ob("prog"), domC=id2ob("chk"), warn=id2ob("warn"), dok=0, per=0;
function rePlus(passw){
var bitM = [0,0], rank = [0,2,3,3], reg1 = passw.match(/[a-z]/g);
reg1=(reg1 != null)?reg1.length:0;
if (reg1!=0) ++bitM[1];
bitM[0]=rank[Math.min(reg1,2)];
reg1=passw.match(/[A-Z]/g);
reg1=(reg1!=null)?reg1.length:0;
if(reg1!=0)bitM[1]+=2;
bitM[0]+=rank[Math.min(reg1,2)];
reg1=passw.match(/[0-9]/g);
reg1=(reg1!=null)?reg1.length:0;
if(reg1!=0)bitM[1]+=4;
bitM[0]+=rank[Math.min(reg1,2)];
reg1=passw.match(/[\x20-\x2f\x5b-\x60\x7b-\x7e]/g);
reg1=(reg1!=null)?reg1.length:0;
if(reg1!=0)bitM[1]+=8;
bitM[0]+=rank[Math.min(reg1,2)];
return bitM;}
function checkPass(passw) {
var passAry=["password","12345678","baseball","prettygirl","maverick",
"football","trustno1","beautiful","xxxxxxxx","qwertyui","starwars",
"hardcore","funnygirl","butthead","steelers","supergirl"];
if(passAry.indexOf(passw)>-1) {
warn.innerHTML = 'This password is NOT allowed - "'+passw+'"';
warn.style.display = "block";
id2ob("passIn").value="";
domPs.innerHTML="";
domPs.style.width="1%";
setTimeout(function(){ warn.style.display = "none"; }, 3500);
return;
}
var perc = rePlus(passw), spread=perc[1];
perc=(passw.length+(perc[0]*0.65))/16.5;
perc=Math.min(Math.round(perc * 98),100);
domPs.style.width=perc+"%";
if(dok==1& passw.length<8){
domC.innerHTML=" less than 8 ";
domC.style.backgroundColor='red';
dok=0;
}
if(passw.length>7){
domC.style.backgroundColor="#2fe868";
domC.innerHTML=" length OK";
dok=1;
}// perc>73&
if(passw.length==7&perc<73&spread<15){
passw="You might add ";
if((spread&1)==0)passw+="a small letter, ";
if((spread&2)==0)passw+="a Capital, ";
if((spread&4)==0)passw+="a number, ";
if((spread&8)==0)passw+="puntuation ";
warn.innerHTML = passw;
warn.style.display = "block";
//alert(passw);
} else if(passw.length>7 || passw.length<7)warn.style.display="none";
if(perc<25){domPs.style.backgroundColor="#d41010";domPs.innerHTML="useless";return;}
if(perc>95){domPs.style.backgroundColor="#38ff70";domPs.innerHTML="STRONG security";return;}
if(perc>83){domPs.style.backgroundColor="#98eaa1";domPs.innerHTML="medium-strong security";return;}
if(perc>73){domPs.style.backgroundColor="#bfcf91";domPs.innerHTML="medium security";return;}
if(perc>49){domPs.style.backgroundColor="efb861";domPs.innerHTML="weak";return;}
if(perc>25){domPs.style.backgroundColor="#ff7600";domPs.innerHTML="very weak";return;}
}
</script>
ASKER
I appreciate the feedback and thought you put into the response. This Q certainly isn't meant to be an exhaustive and complete "strength meter". I am trying your code out as well right now.
Drop box actually publishes a framework (in several lang's) that is very robust I could use, and we have our developers learning from that code: https://github.com/dropbox/zxcvbn but this Q is a small session for a non-techie crowd and this simple JS get's the message across very well I think.
-rich
Drop box actually publishes a framework (in several lang's) that is very robust I could use, and we have our developers learning from that code: https://github.com/dropbox/zxcvbn but this Q is a small session for a non-techie crowd and this simple JS get's the message across very well I think.
-rich
Open in new window