Start reading the news and you are bound to read about another data breach involving user credentials. Whether you get any details about how the passwords (that were stolen) were stored, we can assume that in many of these cases that they were not well protected. Maybe they were stored in clear text (no, it can’t be true), or use weak hashes. Passwords hold the key to our access to most applications. What are you doing to help protect them?
First, lets just start with recommending that the users don’t re-use their passwords, ever. Don’t share them across applications, just don’t. Pick a password manager or some other mechanism to allow unique passwords for each application. That doesn’t mean using summer2015 for one site and summer2016 for another. Don’t have them relatable in any way.
Now that we have that out of the way, how can the applications better protect their passwords? Lets look at the storage options:
- Clear Text
While this may seem harmless, since the data is stored in your highly secured, super secret database, it is looked down upon. As a developer, it may seem easy, throwing a prototype together to have the password in plain text. You don’t have to worry if your storage algorithm is working properly, or if you forget your password as you are building up the feature set. It is right there in the database. While convenience may be there, this is just a bad idea. Remember that passwords should only be known by the user that created it. They should also not be shared. Take an unauthorized breach out of the picture for a moment, the password could still be viewed by certain admins of the system or database administrators. Bring a breach back into the picture, now the passwords can be easily seen by anyone with no effort. There are no excuses for storing passwords as plain text. By now, you should know better.
Another option commonly seen is the use of reversible encryption. With encryption, the data is unreadable, but with the right keys, it is possible to read the actual data. In this case, the real password. The encryption algorithm used can make a difference on how long it takes to reverse it if it falls into the wrong hands. Like the clear text storage, the passwords are still left exposed to certain individuals that have access to the encrypt/decrypt routines. There shouldn’t be a need to ever see the plain text version of the password again, so why store it so that it can be decrypted? Again, not recommended for strong, secure password storage.
Hashing is process of transforming the data so that it is un-readable and not reversible. Unlike when the data is encrypted, a hashed password cannot be transformed back to the original value. To crack a hashed password you would typically run password guesses through the same hashing algorithm looking for the same result. If you find a plaintext value that creates the same hash, then you have found the password.
Depending on the hashing algorithm you use, it can be easy or very difficult to identify the password. Using MD5 with no salt is typically very easy to crack. Using a strong salt and SHA-512 may be a lot harder to crack. Using PBKDF or bcrypt, which include work factors, can be extremely difficult to crack. As you can see, not all hashing algorithms are created equally.
The salt, mentioned earlier, is an important factor in hashing passwords to create uniqueness. First, a unique, randomly generated salt will make sure that if two users have the same password, they will not have the same hash. The salt is appended to the password, to basically create a new password, before the data is hashed. Second, a unique salt makes it more difficult for people cracking passwords because they have to regenerate hashes for all their password lists now using a new salt for each user. Generating a database of hashes based on a dictionary of passwords is known as creating a rainbow table. Makes for quicker lookups of hashes. The unique salt negates the rainbow table already generated and requires creating a new one (which can cost a lot of time).
The salt should be unique for each user, randomly generated, and of sufficient length.
As I mentioned earlier, using MD5, probably not a good idea. Take the time to do some research on hashing algorithms to see which ones have collision issues or have been considered weak. SHA256 or SHA512 are better choices, obviously going with the strongest first if it is supported. As time goes on and computers get faster, algorithms start to weaken. Do your research.
The new standard being implemented and recommended is adding not only a salt, but a work factor to the process of hashing the password. This is done currently by using PBKDF, BCRYPT, or SCRYPT. The work factor slows the process of the hashing down. Keep in mind that hashing algorithms are fast by nature. In the example of PBKDF, iterations are added. That means that instead of just appending a salt to the password and hashing it once, it gets hashed 1,000 or 10,000 times. These iterations increase the work factor and can slow down the ability for an attacker to loop through millions of potential passwords. When comparing BCRYPT to SCRYPT, the big difference is where the work factor is. For BCRYPT, the work factor effects the CPU. For SCRYPT, the work factor is memory based.
Moving forward, you will start to see a lot more of PBKDF, BCRYPT and SCRYPT for password storage. If you are implementing these, test them out with different work factors to see what works for your environment. If 10,000 iterations is too slow on the login page, try decreasing it a little. Keep in mind that comparing a hash to verify a user’s credentials should not be happening very often, so the hit is typically on initial login only.
Password storage is very important in any application. Take a moment to look at how you are doing this in your apps and spread the word to help educate others on more secure ways of storing passwords. Not only could storing them incorrectly be embarrassing or harmful if they are breached, it could lead to issues with different regulatory requirements out there. For more information on storing passwords, check out OWASP’s Password Storage Cheat Sheet.
Keep in mind that if users use very common passwords, even with a strong algorithm, they can be cracked rather quickly. This is because a list of common passwords will be tried first. Creating the hash of the top 1000 passwords won’t take nearly as long as a list of a million or billion passwords.