Everything You Ever Wanted to Know About Password Security (And Two Things You Didn’t)

Andrew Burian
Axiom Zen Team
Published in
7 min readNov 29, 2016

--

Passwords. Can’t live with them, can’t live without them, and overall we’re still really bad at working with them at all.

https://github.com/usnistgov/800-63-3/tree/nist-pages/sp800-63b/media

Passwords, or more formally “memorized secrets,” are and will continue to be completely ubiquitous in any application that authenticates users. Even as more and more applications prefer to push the burden of verification off onto another OAUTH2 service, or as biometrics like fingerprints and facial recognition start to look like tempting alternatives (they aren’t), at some point in your development life you will need to interact with a good old username and password combination. The data is in, and a mind boggling number of applications continue to fall flat on their face when it comes to doing this securely.

Recently I’ve started following the progression of this NIST Digital Authentication Guidelines document (which at the time of writing is still a draft), an excellent guide for what you should and should not be doing with passwords and other forms of authentication. If you’re a standards geek like me, feel free to read the document in its entirety, but if you’re not I’ll summarize some highlights, mixed with my own experience developing applications.

Bad practices make me cry

Let’s start with the do-nots. It continues to amaze me when I encounter these in the wild, on sites and apps that you’d really think would know better.

Password composition requirements: Stop it (the only exception being a minimum password length of 8 characters). Other than that, NIST themselves recommends “[n]o other complexity requirements for memorized secrets.” Requiring users to have x number of special characters and y mixed case may seem like a good idea initially, and most applications that require this do so with good intentions, but research has shown that the average user is pretty bad at making passwords (surprise) and as soon as restrictions like this are imposed, “users respond in very predictable ways” that lead to passwords no stronger than if the restrictions were not present at all. They’re just annoying.

Character set restrictions: This is a capital sin. I will often write strongly worded emails to any service that has restrictions on password length, or only allows a select set of special characters. It’s a sure indication that the underlying password handling is horribly, horribly broken. Your passwords should be able to handle completely arbitrary data. If I want to use a string of unicode emoji as my password, that’s my poor life decision to deal with, but a completely valid password for you to process. If you’re worried about SQL injection or XSS vulnerabilities that might result from this, you’re doing it wrong.

Case and point https://xkcd.com/1700/

Password hints: Hopefully at this point no one thinks this is a good idea. The Windows login screen seems not to have gotten the memo, but if you’re taking security design pointers from Windows, I have a longer article to write for you.

What you should do

While I could write for days about the things you shouldn’t do with passwords, handling passwords correctly actually isn’t that hard. A correctly done password system is one that’s fundamentally unable to mess up even if you try.

Salt, hash, iterate, store: This is the only way to deal with password storage. However, it still leaves the exact details of hashing algorithms, salt lengths, and iterations up to the developer, and there still things can go astray. More on this in a bit.

Password blacklist: This actually surprised me to see in the NIST guidelines, but they do support “disallow[ing] some choices of memorized secrets based on their appearance on a blacklist of compromised values.” I have mixed feelings about this, but statistically, with a large enough user base, a disappointing percentage are going to believe “monkey” is an ok password to use. If you’re willing to risk bothering some of your less security minded users, run their password against the first 100,000 entries in the RockYou wordlist and reject it if it makes an appearance.

Pitfalls of storing passwords

When it comes time to write the password to the database, this is the most common place for applications to misstep.

If you have ever considered, even just for a moment, that your database is in your control, behind your firewall, and that this project is “just a hack” or not that important, and that because of that you can leave the password in plaintext in the database, close your computer and slowly walk into the ocean.

Rather than being stored in plaintext, the password needs to be hashed with a strong complex hashing algorithm. SHA1 is at this point getting a little old and small to be used for password hashing, so choose a hash from the SHA2 suite or SHA3 of sufficient length. MD5? Back to the ocean with you.

The next place problems can arise is if passwords are hashed, but that’s it. It’s relatively easy to precompute a whole pile of password hashes, and then do a dictionary lookup on it. This is called a rainbow table attack, and it’ll wreck you almost as fast as leaving the passwords unencrypted.

So you did some quick Googling and learned the concept of a salt. A good salt is 4 or more bytes of truly randomly generated data. You’re now resistant against rainbow tables, but we have a long way to go yet. Hash functions are by design fast and efficient functions to perform. With GPU-based acceleration, an attacker is going to tear through passwords that have been salted and hashed at a rate of thousands of guesses a second. You need to not only hash once, but iterate the hash thousands of times before it will start to hold up under attack.

GPU based password cracking setup http://heim.ifi.uio.no/hennikl/passwords12/www_docs/Jeremi_Gosney_Password_Cracking_HPC_Passwords12.pdf

At this point, if you’re busy making a checklist of things to implement in your password storage system, stop. The short answer to how to store a password is with a well developed, tested, and audited tool that already exists. Never spin your own crypto, you’ll get it wrong.

Password storage made easy

There are two ways to store a password that I can recommend. One is to use the tried and true bcrypt function, which will salt, hash, and iterate for you, and return to you a single safe string which you can store directly into the database. The only gotcha with bcrypt is the “cost” value. This is telling bcrypt how many iterations of hashing to go through before finishing (though it actually does 2^cost iterations). bcrypt has a really nice trick up its sleeve when it comes to this cost, though - it stores the value of the cost used to generate the hash in the resulting string itself. This means in the future, if the cost you started with is no longer enough, the next time the user logs in you can determine if their hash is out of date and quickly rehash it to upgrade its security. No user action required, same password, but easily upgraded storage security.

What value should you set your bcrypt cost to? As high as you can tolerate. In the age of microservices we’ve arrived at a weird place where the processing power of the application doing the login has dropped. So keep in mind your attackers are going to outgun you by a factor of hundreds, and set your cost high enough that it doesn’t take you too long to check, but as high as possible to resist attack.

It’s easy, trust me

If you have no other specific requirements for password storage, I would go no further and use bcrypt. The only situation where I might deviate from it is in extremely regulated industries where your password storage is going to get audited and have to meet compliance standards. In that case, you may occasionally encounter a regulation authority that doesn’t recognize bcrypt. You can instead use the PBKDF2 algorithm with at least 10,000 iterations, and 4B of truly random salt. PBKDF2 also allows you to choose which hashing function to use in the key derivation. I would recommend using SHA512 over SHA1 or SHA256. SHA512 goes a long way in mitigating GPU based brute force attacks (currently). Most GPUs can easily perform the 32b operations that underly the SHA256 hash, but struggle through 64b operations like those in SHA512.

In conclusion

Read more standards. They’re good for your eyesight and make you more fun at parties.

When choosing passwords, don’t impose composition restrictions on them, and be ready to receive a unicode string of any length. In security sensitive work, feel free to employ a blacklist of passwords, and in all cases they should be at least 8 characters long.

When storing passwords, never write your own cryptographic operations. Use well understood and proven technologies like bcrypt and PBKDF2.

Think security early. Hacks become projects, which then become products, which then get brought to their knees because one person didn’t read this post.

— —

Andrew is an Internet Mechanic with Axiom Zen. Interested in sharing a workplace with him? Axiom Zen is hiring!

--

--