This site uses third-party cookies, learn more or accept
dark light

Your Password Are Weak - Make Them Better With JavaScript

Written by Max Pelic, updated on

Wondering how to implement the perfect JavaScript password strength checker? Stay tuned for a working implementation, or to use the open-source one I created.

Last week I was learning about password security, and it got me thinking about password security checks on sites. Ya know, those pesky requirements for "at least 8 characters" and "please include a number of symbol" and so on. Now, I'm not saying those are bad requirements (though they sure can be annoying sometimes, especially if you're using a method like my word-based password generator). The length requirement makes a lot of sense - every extra character is hundreds of extra possible combinations, and extending the length of the password makes it exponentially hard to brute-force. And having numbers and/or symbols increases the possible characters, which also makes it hard to brute-force. But neither of these account for another common type of attack, a dictionary attack.

A dictionary attack, or rainbow table attack, uses passwords found in data breaches to try to break into an account. For example, "P@ssw0rd" is a common password, so guessing that would be more likely to break into an account than something like "W&gsu2ir". Notice, though, that each of those examples follows the same pattern - one capital letter, a symbol, some lowercase letters, a number, and two more letters. To a simple password strength checker, these passwords seem equally strong.

So, how can we do better? Can we make a password strength requirement that accounts for commonly used passwords? A first (bad) approach might be to compare passwords with other passwords on the system, because hey, if two people have the same password, it's probably not a good password. However, as you hopefully noticed, that would be a huge security issue. If you tell someone that their password is already in use, they could try that password with other email addresses or usernames to break into some unsuspecting user's account. Another option someone might try to implement is to download a list of common passwords, and compare the generated password to each of them. However, that list could be huge (for example, one I found was, when compressed, over 10 gigabytes.

Enter the beautiful free API site Have I Been Pwned.. Have I Been Pwned not only allows someone to visit their site and check if their password was found in a data breach, but it also offers a free endpoint where you can send the first few characters of a hashed version of the password, and it will return a list of passwords matching that prefix, along with the frequency of the passwords in data breaches.

With a little JavaScript, you can implement this in a password security check, without using any server resources of your own.

The Implementation

Although it may seem simple at first, there are actually a few steps required to implement a security check like this. First, the script needs to generate an SHA1 hash of the password to send to the API. Luckily, the site webtoolkit.info offers a free JavaScript implementation of this function with a wonderful open-source license.

Once you have the SHA1 function, you can query the API my making a GET request to https://api.pwnedpasswords.com/range/{prefix}, with {prefix} replaced with the first 5 characters of the hash. Then you can check if any of the results match the remaining hash of the password (this way, you never send the password's hash over the internet, only a small portion of it).

The implementation might look something like this:

1async function isSafe(password){

2 let hash = SHA1(password)
3 let prefix = hash.substring(0, 5), suffix = hash.substring(5);
4 //use the wonderful fetch() function to make this really easy (and asynchronous)!
5
let request = await fetch("https://api.pwnedpasswords.com/range/" + prefix);
6 let hashes = await request.text();
7 hashes = hashes.split("\n");
8 for(let j = 0; j < hashes.length; j++){
9 if(hashes[j].startsWith(suffix)){
10 //password found, yikes!
11
return false;
12 }
13 }
14 //password was not found
15
return true;
16}

If you don't want to implement this yourself, don't worry, I've got you! I created an open-source implementation of this (along with a way to specify other password requirements) on GitHub. I also have an example implementation of it that you can test your own passwords with

Anyway, I hope you are able to learn something from this! Whenever possible, when creating an account, you should implement 2-factor authentication. That way, even if your password is weak, you have that extra layer of security that will keep your valuable secrets hidden. And if you're creating a password strength requirement, please use a service like Have I Been Pwned to make sure the user is not entering a common, yet seemingly secure password.

Share this article:

Previous Article: Wordle - Looking Back

Next Article: The Better Version of an XMLHttpRequest