If you’re designing a login system, then please store passwords correctly.While I’m not an expert at this, I think I’m pretty good, but you should still do your own research.
Why it’s important to store passwords properly
Storing passwords securely can seem difficult, but it is extremely important. Even if you have a website that does not store personal information, people use the same password on many sites, which may include Twitter, Google, Facebook, or even their bank. You have to assume that your database can be broken into, and take every precaution to ensure that even if the database is breached, no passwords can be stolen. If you think this is impossible, read to the end. If not, still read to the end.
This is the easiest, but also the worst possible way to do it. Basically, this is just taking the password, and putting it directly in the database. Checking passwords is made really easy; all you need to do is check the entered password, and what’s in the database. If it matches, you know the password is correct, and allow the user to login. This also requires the least processing power of all the other methods, as the password is not modified in any way before being put in the database, or when checking if the password is correct.
Yes, this is in the what NOT to do section. This may seem like the obvious solution; the passwords in the database aren’t readable without decrypting them first. Great, but how do you decrypt them? In order for this to work, the password has to be in the program, or even worse, the database. If an attacker gets server access, or database access if the key is stored there, they can decrypt the passwords. Once the passwords are decrypted, the attacker can login or sell them, the same outcome as storing passwords in plaintext.
While this is a bit better in terms of security, I’d actually say it’s worse overall. Not only is it providing a minimal security benefit over plaintext, it uses more resources for encrypting and decrypting the passwords. So, don’t do this either.
Hashing without a salt
If you don’t know what a salt is, you’ll learn about that in the next section 🙂 .
Ok, storing passwords in plaintext, and encryption is bad, so, what’s wrong with hashing? The simplest way to describe hashing is one-way encryption. For example, entering
abc123 into the
md5 hashing algorithm results in the following:
which is not human-readable. Entering
abc123 again will result in the same output, making it appear to be a good way of storing passwords. The only way to get the password is by trying every possible combination until you get the same hash. There are two problems with hashing in general, and an additional one with the example I used:
- An attacker can see if users have the same password. Since the hash of the same password is the same, an attacker can see how many users have the same password. Then, all they need is to crack one, and they know the other accounts they can log in as.
- There are lists of millions of hashes accessible online, called rainbow tables. This means that you can figure out the password a user has by simply searching the hash in one of many databases available for free online. Combined with problem #1, and you can begin to see why this is not such a good idea.
- In case you’re wondering, the problem with the example I provided is that I’m using the
md5algorithm, which is no longer deemed secure.
Hashing with the same salt
A salt is basically a random string added to the password before it’s hashed. This makes the hash different than the hash of the plain password, which takes care of problem #2 I mentioned above. However, there is still problem #1: the same password is still the same hash. If multiple users have the same password, an attacker can figure that out. Then, they can attack the most-used hashed, which will lead to the most used password. If the salt is long and random enough, it can take years and years to crack, but once it is cracked, an attacker knows which accounts they can log in as.
Also, there are rainbow tables with salts available, so if the salt is too short, or not random enough, there may be pre-made rainbow tables available, in which case this is no better than hashing without a salt.
Hashing with a different salt for each user
The best way to store passwords is to add a unique, long, random salt to each password before hashing. If you’re wondering how to keep track of so many salts, there are multiple ways, but I’ll get into that in a bit. Storing passwords like this solves all of the problems of hashing without a salt. Attackers don’t know if multiple people have the same password, because even if two users have the same passwords, they have different salts, and therefore different hashes.
Now, onto how to store salts. The great thing about salts is that they can be available to the public without affecting the security benefits provided by them. Because they are unique for each account, an attacker would need to brute force each hash, even if it’s of the same password. Anyways, the two main ways to store salts are:
- In the database
- Along with the hash
Method 1 is probably the most portable; as you can do it in nearly any language. Simply add a
salts column to your database, and you’re good to go. All you need is to get the salt, and add it to the entered password before comparing. Method 2 is easiest done in PHP, which provides a built-in function called
password_hash, which takes care of everything for you.
Here are some examples in PHP:
To hash and salt the password, simply get the password into a variable, and run the following before storing:
This will hash and salt the password, without the need to store the salt separately.
To verify the password, simply get the entered password as a variable, and the hashed version from the database, and run:
Or, in a more complete example:
echo "Logged in!";
echo "Oops, wrong username or password";