I read this article about password hashing using bcrypt as the recommended method. The advice is similar to what they're saying on hacker news about not using something like SHA2+salt. There are other answers on the infosec StackExchange about why we shouldn't use something like SHA-256. The generally accepted knowledge is:

SHA2 is fast, which is bad (bcrypt is purposefully slow so that we can get around Moore's law)

As you know, if we use bcrypt, we to hash something with a cryptographically random salt, we might get this string: $2a$13$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm, and the salt is contained in that string.

My question is a bit multifaceted:

  • If an attacker gains access to the database with write access, they could just re-write someone's password in the table with their own hash and login to that user's account, right? Unless that's not their specific objective (for example, maybe they don't want anyone to know that they accessed the database). Or if they have read-only access, I guess that's a different story.

  • Aside from the fact that bcrypt is purposefully slow, is there any other advantage to storing the salt in the same hash as the password as opposed to having both user.hash and user.salt in one record if I didn't use bcrypt? Or in that case is it generally best practice to store hashes and salts in separate tables/databases (then presenting the disadvantage of multiple table/database lookups as mentioned in one of the comments)?

We also get the issue that bcrypt presents minor (yes, within the milliseconds range) performance issues (purposefully) when performing lookups, which is negligible in most cases, but it seems the only protection we really get from bcrypt is making it difficult to batch process an entire user table and covertly log into users' accounts (or sell their information, or whatever). Why not just use something like SHA2+salt then?

up vote 6 down vote accepted

Gaining read-only access is a much more likely scenario than write access - after all, read access to an old backup or test server somewhere is nearly as good as read access to the real server. (since people don't change their passwords often enough)

Also though, one account nearly anywhere (unless you're a banking site) isn't that valuable. Hundreds of thousands of accounts, though - now you're talking. And while a single db write might go unnoticed, thousands of anomalous db writes - especially with every person whose account was written to now being unable to log in - generally will get noticed. Furthermore, cracking your user's password gets access to everywhere that user has used that id/password combination, which is likely to include sites more valuable than yours.

As for your record storage scheme, the main reason to store the output of your password hashing function in one blob that the rest of the database doesn't interpret (as opposed to separate salt and hash fields) is that you don't want to encode your hashing algorithm into your database. What if tomorrow you wanted to change to PBKDF2, or scrypt, or in fact bcrypt? Better to let an existing vetted password hashing function do the interpretation than to tie yourself to hash functions that fit the format of your current salt + commodity hash method. Instead, if you just have a field for algorithm and another field that is just "string to pass to the algorithm along with a password to see whether the password is good" (you might call this field hash or saltNhash), then you can even upgrade users transparently as they log in.

As an aside, salted SHA2 is acceptable password security if you're standing up a web service in 1995. Twenty years on, use bcrypt or something even better. Salted commodity hashes (such as MD5, or the SHA* family) are vulnerable to cheap GPU-based attacks, to the point where rainbow tables aren't economically efficient any more - it's cheaper to just run the dictionary attack as needed than to keep around a giant table that's trivially defeated by salting anyway.

Password hashing is something other people have already worked out in detail for you. You wouldn't write your own crypto or your own video compression algorithm; don't make the mistake of ignoring the good solution in front of you in exchange for years of discovering subtle corner cases people have already designed for.

While using a sufficiently long and random salt will prevent a precalculation attack (eg: rainbow tables), it will not protect against a simple dictionary attack on the password. Consider the scenario where an attacker gets a copy of the database. If the passwords are just salted SHA2, it may be worth their effort to go after some number of the passwords. This could be done by calculating the hashes for the top 100 most common passwords for each salt that is used in the database. Alternatively, if one account is targeted, the attacker can perform an in-depth attack on that one hash. Using bcrypt dramatically increases the computation, time, and monetary cost of executing such an attack.

As you point out, secure password storage does not help if the attacker gets write access to the password table or the database in general. When that occurs the attacker can use more direct attacks.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.