Secure Password Storage - a Myth?
With Sony’s recent fiasco (PSN hacked, user data, including passwords stolen) the old topic of password storage is in spotlight again. Is it really that hard to store passwords securely? Obviously not. Let me show you how a post-stone age developer would solve it and some of the cryptographic background.
First of all, what’s so wrong with storing passwords as-is (plaintext)?
Basically, it offends your users’ right to privacy. You, the sysadmin, the IT guy or a hacker can get access to it. It’s a huge security risk in your service (the hacker can then impersonate your users easily) and also many users use the same passwords on many sites, so you might easily be posing a security threat to other sites, companies. Moreover, many people choose personal passwords - sensitive insights about them is thus revealed by their password choice. As a summary, it’s both unethical and insecure to store plaintext passwords.
What’s the solution then? We have to be able to verify the user somehow upon login, don’t we? True, but for this, the password itself is of no information. The real information in the authorization process is whether the person on the other end of the line knows the password or not. It’s a huge difference. So how do we verfiy the knowledge itself without actually storing the information? We need something that produces some obfuscated info from the original, sensitive plaintext data (password). We have many possible candidates for this, e.g. simple checksum, crc , the point is that it’s like a function which always produces the same output from a single input. With such a function at hand we only need to store the result of the function, the obfuscated info, then during authorization use the same function on the typed-in password and see if the outcome is the same as the stored value.
This is only one part of the whole story, though. Simple checksums and crc’s are not considered secure, because when someone gets hold of your database containing the obfuscated values, there are mathematically very easy (simple and fast) ways to recover the original password from them. Enter secure hashes.
A secure (also called cryptographic) hash is an one-way function which has the following properties:
- it is easy to compute the hash value for any given message (fast forward calculation),
- it is infeasible to generate a message that has a given hash,
- it is infeasible to modify a message without the hash being changed,
- it is infeasible to find two different messages with the same hash.
Some of the best known secure hash algorithms are MD5 and SHA*. Their usage is quite simple: take your favourite language (or use MySQL’s, etc. built-on functions), get a lib for it if these crypto functions aren’t built-in, when the user registers, calculate the hash, store it in your DB and when it’s stolen, no hacker will be able to recover the password.
Really? Well, not really. Simple MD5 and SHA-1 are still quite vulnerable. There’s a clever attack on them, known as the rainbow table attack. Basically rainbow table is an efficient data structure to store precomputed hash chains. It’s like a cache for brute-force trial attack and it’s proven to be quite effective.
OMG, what can I do then?
Don’t panic. It’s not a lost fight. Fortunately rainbow table efficiency can be nulled with using a very simple method: salts. Salting is adding a pre-generated (used as a constant in the registration-authorization cycle) string which you automatically add (concatenate) to the passwords before you’re giving them to the secure hash functions. For example given your pre-generated salt is ‘iw8ahphieBa7aesahLeenaKae3lae0ee’, when the user registers with the password ‘i love bunnies’, you’ll be hashing like this: stored_hash = md5(‘I love bunnies iw8ahphieBa7aesahLeenaKae3lae0ee’).
Even better, periodically ‘change’ your salt. Say at every 10th user you generate a new salt and from that time you use it. Of course this method requires storing additional information, like salt history, but it’s a quite secure solution.
Well, I hope you agree by now that secure password storage is not a myth, it’s a quite easy method. Please share your experience and further thoughts!
A few really nice comments came up, and after reviewing some solutions I feel you’re right - currently the best way is to use bcrypt. Thanks for the great comments and suggestions guys!