A lot of websites display the strength of the password chosen by the user on their registration forms. The goal of this practice is to help the user choose a better, stronger password which cannot be guessed or brute-forced easily.
In this recipe, we're going to make a password strength calculator. It will determine the password strength by calculating the number of brute-force attempts that a potential attacker must make before guessing the password. It will also warn the user if his password is in a list of 500 commonly used passwords.
Before we begin, its important to look at how we're going to calculate the number of brute-force attempts that an attacker must make. We're going to take a look at two factors: the length of the password and the size of the character set used by the user.
The size of the character set can be determined as follows:
Let's write the HTML and JavaScript code:
password
input, then add a div
element, which we will update with the password strength result. Common passwords will be included via a script named common-passwords.js
:<!DOCTYPE HTML> <html> <head> <title>Password strength calculator</title> </head> <body> <input type="password" id="pass" value="" /> <div id="strength">0 (very poor)</div> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script type="text/javascript" src="common-passwords.js"></script> <script type="text/javascript" src="example.js"></script> </body> </html>
The common-passwords.js
script is not included here, but can be found in the supplementary code.
example.js
:$(function() { function isCommon(pass) { return ~window.commonPasswords.indexOf(pass); } function bruteMagnitude(pass) { var sets = [ { regex: /d/g, size: 10 }, { regex: /[a-z]/g, size: 26 }, { regex: /[A-Z]/g, size: 26 }, { regex: /[!-/:-?[-`{-}]/g, size: 24 }, ]; var passlen = pass.length, szSet = 0; sets.forEach(function(set) { if (set.regex.test(pass)) { szSet += set.size; pass = pass.replace(set.regex, ''), } }); // other (unicode) characters if (pass.length) szSet += 20; return passlen * Math.log(szSet) / Math.LN10; } var strengths = ['very poor', 'poor', 'passing', 'fair', 'good', 'very good', 'excellent']; function strength(pass) { if (isCommon(pass) || !pass.length) return 0; var str = bruteMagnitude(pass); return str < 7 ? 0 // very poor : str < 9 ? 1 // poor - 10 million - 1 billion : str < 11 ? 2 // passing - 1 billion - 100 billion : str < 13 ? 3 // fair - 100 billion - 10 trillion : str < 15 ? 4 // good - 10 trillion - 1 quadrillion : str < 17 ? 5 // very good - 1-100 quadrillion : 6; // excellent - over 100 quadrillion }
div
element indicating password strength when a key is pressed in the password
field:$('#pass').on('keyup keypress', function() { var pstrength = strength($(this).val()); $("#strength").text(pstrength + ' (' + strengths[pstrength] + ')'), }); });
The calculation is split into two parts: checking for password commonality and password complexity.
We check if the password is common simply by checking if it can be found in the commonPasswords
array provided by common-password.js
. Array#indexOf
returns 1 if the entry was not found. The bitwise not operator ~
turns that value into zero, which evaluates to false. All the other numbers greater than or equal to 0 will have negative values, which are true values. Thus, the entire expression returns true if the password is found in the array.
In the bruteMagnitude
function we calculate the password's brute-force order of magnitude using the passwordLength
and character setsize
methods:
magnitude = log10(setSize passwordLength) = passwordLength * log10(setSize)
This is an approximate order of magnitude of the number of passwords that a brute-force password attacker must try to guess the password.
Based on this information, we can now give an actual password strength. If the password is among the top 500 common passwords, it will be classified as poor. Otherwise it will be classified according to its brute force magnitude using the following table:
Magnitude |
Number of passwords |
Rating |
---|---|---|
Less than 7 |
Less than 10 million |
Very poor |
7 to 8 |
10 million to 1 billion |
Poor |
9 to 10 |
1 billion to 100 billion |
Passing |
11 to 12 |
100 billion to 10 trillion |
Fair |
13 to 14 |
10 trillion to 1 quadrillion |
Good |
15 to 17 |
1 to 100 quadrillion |
Very good |
Greater than 17 |
Greater 100 quadrillion |
Excellent |
The classification, along with the descriptive text will be updated on every key press and displayed to the user below the password field.
3.129.194.123