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.
Also, secure your backups. Many, many attacks focus on MYSQL dumps, so go do all the stuff mentioned here. See you next Wednesday when you're done with all that.
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.
Comments
I think you're refering to "Le Monde" and not "La Monde".
Thanks, Pierre! Fixed. :)
Good post. Short but contains a good list of things to do. Especially like the part about distributed data storage. Certainly adds complexity and some risk if you don't get it right but prevents the password file dump that seems to have bitten a lot of companies in the past.
Favor to ask. You have a link to password reset flow but how about a followup post with a set of diagrams on good/bad flows. Wonky but something I've been interested in seeing for a while.
Great idea, Ken! We are as well, and have actually been thinking a lot about different user email workflows (not only because its a feature, but because we also want to make signup for Stormpath easier). I have added that to the blog list.
> Enforce password strength by requiring a blend of numbers, letters, cases and symbols
That's arguable. (XKCD comes to mind). It's better to enforce large enough minimal password length, than enforcing using hard to remember symbols mixture.
even better is to enforce a minimum entropy, it's incredibly easy to calculate and doesn't make users jump through hoops to produce un-memorable passwords that they will just write down on a post-it.
Hey, great post!
One detail I wanted to question was the point in "Level 3: Computational Cost". It says that increasing the hash calculation time exponentially increases the time it takes for a brute force attack.
I think it is actually a linear increase. That said, a linear increase is a significant deterrent if the factor is something like 10^9.
Hi Wheremiah,
The exponential increase is experienced when attacking multiple passwords, not just one.
Cheers,
Les
The multiple data stores and private key encryption are nice theoretical advantages, if your data center happens to be raided by armed insurgents. But most attacks come from interactions with running services. If your services is running then it will have access to all those datastores (or else the service wouldn't be running effectively), and also it will have access to the private key used to decrypt your data.
Gaining access to the system completely removes any advantage you might have had from those two techniques.
I have encountered vendors who say they are secure because of their on-disk encryption only to extract plaintext passwords by simple command injection. Or by gaining shell access and inspecting the code. Or, (in the case of one vendor who "obfuscated" their code with various packers) by running their code in a debugger and inspecting memory.
> "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."
Watch me.
"The iterated hash output would effectively take thousands of years of current computing power before one could even begin to brute-force a single Stormpath-secured password hash."
So yeah you can just add another few iterations of SHA-2 and make hackers crack that before getting to the password's hash, or go way overboard and show off your security by encrypting the hashes with some private key. If hackers get database access, it's reasonable to assume they can get that key. Heck, you need the key *every* time you authenticate someone!
Even if they key isn't compromised, there's this: If you use RSA with a key of 4096 bits, you are adding 4096 bits of randomness that an attacker must guess before getting to the hash. Iterate 8 times SHA-512 and you have added the same security. Doing another 8 iterations is very trivial compared to encrypting the hashes and going through the hassle of trying to protect a private key that you'll need upon every log-in attempted by anyone.
One thing must be said though, I can be fairly certain that you'll hash my password. Can't say that about everyone! On the other hand, overkill also makes the people on Hackernews wonder about your competence :P
I know nothing about security and found this a very interesting article but there's something about salting I don't understand:
I assume that a rainbow attack means the attacker has access to the stored password hashes, otherwise how would they be able to tell when a hashed password matches one in their rainbow table. If the attacker has access to the stored password hashes, then surely they would also have access to the stored salts as well? If that is the case, then what is the advantage of having a salt?
Is the idea that the attacker can no longer use pre-computed rainbow tables, and would have to recalculate the hashes for each plain text password in the rainbow table, for each password they're attacking?
Leave a comment