Password security - not the most exciting part of your app. Because its complicated to build well, time-consuming to maintain securely, and because attacks are escalating through cloud technologies, even big companies like Sony and LinkedIn take shortcuts that lead to major security breaches. However, this is incredibly foolhardy: the average cost of a data breach is more than $5.5 Million. We want to lay out some best practices (also on video) to show how password security should be done (from level 0 to 5, with 5 being the most secure), and maybe convince you that you don't want to take on that kind of risk yourself.
Level 0: No Plaintext Anywhere
A big, red flag should go up whenever you see a password in plaintext. While many will claim "no idiot would do this," Sony Playstation last year lost 1,000,000 of their passwords to a simple SQL injection attack, and Yahoo lost over 400,000 plaintext passwords this summer. Bad times. Emails that "confirm account details" - with both username and password in plaintext - are actually less helpful to users than a simple, secure password reset workflow, and if you only need a simple user directory, you can set one up with Stormpath quickly. No plaintext in your database or your notifications! (We mean YOU, French National Bank!)
Level 1: Don't Just Hash It...
Password security is all about what happens in the Black Box of encryption - passwords go in as plaintext, mathematical processes are inflicted upon them, and they come out indecipherable. Hashing is a one-way encryption method that passes your password string through a hashing algorithm and spits out a jumbled value (called a 'digest'). Many people take this value and store it directly in a database, thinking it is much safer than Level 0.
While it's true that it is hard to discover the hash's original value directly, attackers use various techniques, like Rainbow Tables, brute force and dictionary attacks, to more easily find a password's original value. Additionally, simple hashing can also expose duplicate passwords across users (if two users have the same hash, they have the same password). This was the level of protection in use at LinkedIn when they were attacked this summer. Finally, while you could use the MD5 or SHA-1 algorithms for hashing, it has been discovered that these are vulnerable to collision attacks. You should to use SHA-256 or higher. You also need to go beyond simple hashing alone...
Level 2: Salt It!
The best way to strengthen a hash and avoid these evils is through the addition of a securely randomly-generated salt to the hash algorithm. A secure random salt adds additional random bits of data which, when combined with the plaintext input, make the hash output unique. To quote Les, our CTO, "This means you can hash the same password 20 different times, and use 20 different (securely randomly generated) salts, and the hash output will be different every time." Every password should have its own salt and they should be long and complex.
Good password hashing approaches include secure random salts. We like SHA-512, but SHA-256 which has plenty of examples on GitHub has also never had a reported successful attack. Also, interestingly, if you are building anything for the US government, you are required to use the SHA-2 family, which includes both of these badboys.
Level 3: Computational Cost
One of the big reasons salts work is that the increased entropy makes it almost impossible to brute-force a password when you have only the hash output. But what if someone does in fact get access to the hash output and they have dedicated computers to attempt a brute-force attack?
You can increase the time it takes to brute-force a password, making brute-force attempts more infeasible. If you increase the time even only a little - to where the hash computation time is practically unnoticeable to users, say, half or 3/4ths of a second - this becomes a BIG deal for brute-force attackers. It exponentially increases the amount of time it takes to crack multiple passwords.
You can increase the computational time by performing the hash multiple times (e.g. 500,000 iterations), or you can use a hash algorithm like Bcrypt or SCrypt that has a computational time complexity built-in to its approach. Either way, slowing down things for attackers is the way to go with modern computers that can easily have 4 or 8 CPU cores (or more) in a single PC.
This is the level where most advanced developers stop, and sure, we get it, bcrypt (or scrypt) is great. At Stormpath, we provide military-grade security, so we go even beyond this. We'll share some of our advanced methods:
Level 4: Encryption
Stormpath loves to add computation complexity to the hashing process, additional hashing with private securely derived keys, and other secret sauce to make it computationally infeasible for an attacker to crack even a single password. We also encrypt the hash output using a private key - stored in a separate location from the password data - to encrypt the output before storing.
This ensures that not only must the encrypted password must be compromised, but also the encryption key - much harder to do given the separate storage locations. We also rotate the encryption keys on a time-based trigger to ensure that keys are not reused. The encrypted output would effectively take thousands of years of current computing power before one could even begin to brute-force a single Stormpath-secured password. Suck it, hackers.
Level 5: Distributed Data Storage
Finally, we have the big 5. After salting, iterating and encrypting the data, we break up the encrypted hash and store the chunks across separate physical data stores. Our production data stores are protected by multi-factor authentication and other security best practices. An attacker would have to breach all of our related datastores before they could even begin to attempt a brute-force attack on Level-4 encrypted data.
One more no-brainer: process and policy
As the French National Bank demonstrated with their default password "123456", some developers are still allowing super-crackable 8-char passwords. Don't be that guy! I know users don't love passwords like a;#$Soe59Ef9jwq#$, but if you are being smart about where you need authentication and use email as a login (which is easy to remember and trigger a password reset from), its better than being on the front page of Le Monde.
Remember that users re-use passwords across sites and applications, so even if you're not storing critical information, there is a high-probability that password protects something important. You get hacked, and their online banking gets hacked: you're still the bad guy. Enforce password strength by requiring a blend of numbers, letters, cases and symbols. Shameless self-promotion: Stormpath has built-in password strength enforcement so you don't have to build this crap yourself.
This leads me to the final point: securing passwords right is time consuming, risky and expensive -- and its not core to your product. Whether you have a simple application or need to manage security and access across multiple applications, Stormpath can save you a ton of time, numerous headaches and possibly even global embarrassment. Try it now!
Next time, in part 2... backend password security infrastructure.