Passwords. Everybody needs them, everybody uses them. Applications rely on them to prove your identity and protect your information. However, implementing passwords based on authentication on the server is not as easy as some might think.
Of course it should almost go without saying that having a password policy that requires passwords of a minimum length and complexity is essential. Special characters should at least be mandatory, and any system that restricts what characters you can use, or even sets a maximum length on your password should be regarded with suspicion.
Have you ever been to a website and needed to reset your password, only for that website to email you your old password back? This is a serious security problem, as it means your password has been stored either in plain text or encrypted, but using a method that can be reversed. Either case allows someone easy access to your user’s passwords, should your app server or database be compromised.
When Is A Hash Not A Pound?
Passwords should be stored using a non-reversible format. One common approach is use of a cryptographic hash function. A cryptographic hash (as opposed to a #) is a short, usually fixed length value that represents the contents of another value. Any change to the original value results in a change to the short value. Running the original value through the process should always result in the same short value, allowing us to compare what we have stored against what the user provided.
Pour Some Salt On That Hash
In addition to the hash, a salt value – a random chunk of data that varies every time the user’s password is changed – should be added to the hash and stored in the database. This bit of always changing random data added to the hash helps mitigate certain types of attacks. To calculate the hash with a salt, in pseudo code:
$hash = SHA512( $password + $salt)
The $hash and the $salt are typically stored in the database. They can be stored in separate fields, or combined into one, as both the hash and the salt are fixed length. To authenticate a user, we just perform the same operation, and compare the results of that, with what we have stored in the database. This is sometimes called “encrypt and compare“while, in actuality, it’s “hash and compare”.
SHA-512 vs. SHA 256
It used to be fairly common that MD5 or SHA1 algorithms were used, however these have fallen out of favor as attacks against them have been discovered or have become viable. Currently SHA-512 variant of the SHA-2 family is the best available hashing solution, at least according to NIST. NIST also has SHA-3, a next generation hash, in draft status. SHA-3 doesn’t suffer from some of the (currently theoretical) weaknesses in the current SHA-2 hashes.
Why is SHA-512 better than SHA-256? First, it has a much larger address space, so a much smaller chance of collisions (two inputs producing the same output). Second, it’s slower on 32bit hardware. Unfortunately it’s faster on 64bit hardware, which is the norm these days. Why do we want authenticating someone in to be slower? Well, it’s all about limiting the number of tries that can be attempted per second. Regardless of the hashing algorithm used, there’s always brute force attacks against weak passwords, and even strong passwords will eventually fall to brute force. But your app blocks logins after 3 attempts, so we don’t need to take any additional measures, right? WRONG! Locking users out does you no good when the attacker has a copy of your database.
Password Stretching
In order to slow down those brute force attacks we need to stretch out the time it takes to hash a password. Each round should take the previously generated hash, add the password and salt (to help prevent a loss of entropy that would otherwise occur through each step of the loop), and then hash again. So for example, in pseudo code:
$iterations = 10000;
$hash = SHA512($password + $salt);
for ($i = 0; $i < iterations; $i++) {
$hash = SHA512($hash + $password + $salt)
}
$hash = $salt + $hash
You would need to figure out how long this takes on your server hardware, and how fast you want it to be to determine how many rounds you need to perform. The SHA-2 family of algorithms, of which SHA512 is part, is very fast – so you will likely need tens or even hundreds of thousands of iterations.
So now you’re SHA512 hashed, salted, with many iterations – is that good enough? Maybe. If you’ve tuned your number of iterations. And you might even want to tweak that based on the role of the individual user. For example, you may want it to take about 500ms on your server to hash the password when authenticating a regular user, but you might want it to take about 1s for a user with administrative privileges.
Alternatives To Hashing
There is an alternative to cryptographic hashing which can successfully slow some attacks, and may offer higher security depending on your needs. A password based key derivation function creates an encryption key using a password as the base. There are three well known versions: PBKDF2, bcrypt, and scrypt. These all require an iteration count or work factor as inputs to control the performance, and all have different strengths.
PBKDF2 is NIST endorsed, and is very well known, and well researched. NIST has deemed PBKDF2 as “secure enough” for government work. It doesn’t help much with the GPU/FPGA problem, but it is probably the best you can do when you must comply with NIST/FIPS. Most standard implementations use SHA1, as SHA1’s use in this case is permitted, however the PBKDF2 standard allows other approved algorithms such as SHA256 or SHA512. When using an alternative to SHA1, you may need to write your own implementation or leverage a third party component.
Bcrypt has been around for a while, and uses the blowfish algorithm. While it’s not NIST approved, it’s been out there and working for many years without being broken. And by the nature of the way it works it impedes acceleration by GPU. However, in the past 5 years or so FPGA’s with built-in RAM have become common – allowing bcrypt to be efficiently accelerated using off-the-shelf hardware as well.
Scrypt is a relative newcomer, having been invented in 2009. It requires significantly more RAM than bcrypt, thus making it harder to accelerate with FPGA’s. Unfortunately, as the youngest of the bunch, it’s less well studied and proved than bcrypt or PBKDF2, but its use in some crypto currencies may over time prove it out.
Take the time to think about your authentication and authorization systems, password storage, etc. It’s not a glorious job, and it may well be thankless, but that sure beats what might happen if you don’t. Make sure to also be wary of sites that don’t take it seriously.