5 Things Every Developer Needs To Know About Passwords

Until we can get all of our users using a better solution like OAuth or SQRL storing our user’s passwords is going to be a common point of pain for us as developers. In this article, we’re going to discuss how to help our users have good password hygiene and what we should be doing to protect their passwords.

Never Store Passwords in Plaintext

The most important thing we can do is not save passwords in plaintext. If our database is exposed to the internet having passwords encrypted will reduce the chance that our users’ information will be compromised on other sites (as there is a high degree of password reuse across sites). It will also prevent our programmers from getting curious and attempting to use our user’s login information on our site to access their online dating profile or god forbid bank.

There’s old information floating around that passwords can be encrypted using just a hash function like SHA1, SHA256, or MD5. This is no longer the case. These functions provide a degree of protection but because they always provide the same output for a specific input it’s easy to compute a rainbow table (basically the outputs of all inputs) for the most commonly used password.

To improve the security we can add what’s know as salt to the password. This is a precomputed blob of random text that we feed into the hashing function along with the password so even if two users are using the same password they will have different hash values.

$salt = substr(hash('sha256', gmdate('U')), 0, 10);
$encrypted = hash('sha256', $salt . $password);

When we compare the hash we created to the password the user provided us we’ll pull out the first 10 characters so we use the same salt value.

$salt = substr($encrypted, 0, 10);

In our next article, we’ll show how to use PHP’s built-in password functions to use bcrypt to protect passwords so don’t go writing an implementation on your own in the meantime.

Finally, we can use an encryption algorithm that’s either memory intensive or CPU intensive. By using one of these we make it harder for an attacker to compromise our password list. For example, SHA256 runs the algorithm multiple times to make it harder to crack a password.

Prevent Use Of Common Passwords

A common way to gain unauthorized access to systems is for an attacker to guess a username and password combination. They may even already know a username they want to access and they’re just guessing the correct password. They’re not going to start out by guessing “a” and then “b” what they’re going to do is start working down a list of common passwords like “123456”, “password”, and “qwerty”. To help our users help themselves we can prevent them from using the top 200 or more passwords. The list below contains 1,000,000 but obviously, that’s WAY too many.


Prevent Brute Force Attacks

The next piece of advice is to make it hard for attackers to attempt to brute force account credentials using our web application’s login or API. What we want to do is slow down the attackers so they can’t try thousands of combinations an hour. This can be done in a couple of ways.

The first is to keep track of the number of failed attempts an account has had and after five or so attempts we can lock the account for an hour. This will prevent a specific account from being attacked. The downside to this is that an attacker can take advantage of this and switch accounts after the lockout has started and switch back to original account after the lockout has expired. It can also annoy our users who have had their accounts locked if they can’t remember their passwords.

My preference is to create a delay in processing the login request per IP address. To do this, every time we process a login attempt from an IP address and we’ll then wait (using the sleep() function) 0.25*[consecutive number of failed attempts in last hour]^2 seconds before processing the request. The numbers can be tweaked to suit different needs. At the lower end of the failed count which is where most users are going to be the delay is so small they won’t notice. If attackers are running through a lot of combinations they’ll quickly get into the area with wait times over half a minute.

A graph showing how our equation grows exponentially

Favor Long Passwords Over Complex Passwords

A password trend that needs to stop is the complex password. We’ll run into password requirement screens that have 8 rules where the password has to be so many characters long but not longer than another requirement. It will have to has lowercase and uppercase characters, digits, and special characters. If a user hits this screen they’re going to do the least secure thing they can do which is to write their password down somewhere.

A book for storing passwords

Unless the application we’re supporting requires specific password requirements due to a compliance requirement, we always want to make it easy for our users to create hard to crack and yet easy to remember passwords. To this end, we should be allowing them to pick the complexity but pushing them into a long password with 1 special character.

XKCD 936

The Gibson Research Corporation has an online tool that allows us to enter a password and see how long it would take to crack a password. It provides three scenarios. One is an online attack where an attacker would be hitting our website over and over, the next is an offline fast attack scenario where someone has a copy of our user’s passwords and they’re trying on their computer, the last is a massive attack where they’ve farmed out the solution to multiple computers. We’re going to focus on the third situation because it’s the worst-case scenario.

The first thing we’re going to look at is to enter just “longpassword” as the password. In this case, it will take 16.54 minutes for an attacker to find our password if they’re trying every possible password with just a through z lower case.

Password Haystacks with longpassword

If we add a single exclamation point to our password so it’s “longpassword!” and the time to break the password jumps up to a little less than 34 years. Notice how our password is easy to remember and yet still provides 34 years’ worth of protection.

Password Haystacks with longpassword!

As a side note, by just capitalizing the first letters of the words in our password sentence (“longPassword!”) we jump up to 39 centuries and it’s still easy to remember.

Password Haystacks with longpassword! capitalized

To this end, our password screens suggest a password be a minimum of 12 characters and 1 special character.

Support Multifactor Authentication

Two-factor authentication (2FA) is an option all websites should be offering their users. It reduces the chance an account will be compromised if an email and password are compromised on another site not using the suggestions we outlined above. We recommend offering 2FA to all users as an extra precautionary method.

2FA works by giving our users a second way to authentication themselves to our website. This allows us to check something they know which is their username and password and something they possess. This second factor should be a challenge for an attacker to get a hold of.

SMS is the default option for most sites because so many users will have an SMS-capable phone nearby all the time. This is an okay option for sites where the information on the site can’t be used to compromise other sites or doesn’t contain financial information. However, it’s almost laughably easy for attackers to perform a SIM swapping attack (where they associate a SIM in their possession for a target’s account) so it’s not super secure. In cases where a higher degree of security is required it’s best to use an authentication app or device.

What You Need To Know to Nail a Job Interview

  • Never store passwords in plaintext
  • Prevent use of common passwords
  • Prevent brute force attacks
  • Favor long passwords over complex passwords
  • Support multifactor authentication