how salt can be implemented to prevent pre-computa

2019-02-21 07:33发布

问题:

A salt makes every users password hash unique, and adding a salt to a password before hashing to protect against a dictionary attack. But how?

回答1:

The tool you almost certainly want is called PBKDF2 (Password-Based Key Derivation Function 2). It's widely available, either under the name "pbkdf2" or "RFC 2898". PBKDF2 provides both salting (making two otherwise identical passwords different) and stretching (making it expensive to guess passwords).

Whatever system you are developing for probably has a function available that takes a password, a salt, a number of iterations, and an output size. Given those, it will output some string of bytes. There are several ways to actually make use of this depending on your situation (most notably are you dealing with local authentication or remote authentication?)

Most people are looking for remote authentication, so let's walk through a reasonable way to implement that using a mix of deterministic and random salts. (See further discussion below w/ @SilverlightFox.)

First, the high-level approach:

  • Hash on the client against a deterministic salt. The client should never send a bare password to the server. Users reuse their passwords all the time. You don't want to know their actual password. You'd rather never see it.
  • Salt randomly and stretch on the server and then compare.

Here's the actual breakdown:

  • Choose an app-specific component for your salt. For example, "net.robnapier.mygreatapp" might be my prefix.
  • Choose a user-specific component for your salt. The userid is usually ideal here.
  • Concatenate them to create your salt. For example, my salt might be "net.robnapier.mygreatapp:suejones@example.org". The actual salt does not matter too much. What matters is that it is at least "mostly" unique across all of your users and across all other sites that might also hash passwords from your users. The scheme I've given achieves that.
  • Choose a local number of iterations for PBKDF2. That number is almost certainly 1000. This is too few iterations, but is about all JavaScript can handle reasonably. The more iterations, the more secure the system, but the worse the performance. It's a tension.
  • Choose a length for your hash. 32 bytes is generally a good choice.
  • Choose a "PRF" if your system allows you to pick one. HMAC-SHA-256 is a good choice.

You now have all the basic pieces in place. Let's compute some hashes.

  • On the client, take the password and pass it through PBKDF2 with the above settings. That will give you 32 bytes to send to the server.
  • On the server, if this is the account creation, create 8 or 16 bytes of random data as your salt for this account. Save that in the database along with the username. Use that salt, and another set of iterations (usually 10,000 or 100,000 if you're not in Node) and apply PBKDF2 to the data that the user sent. Store that in the database. If you're testing the password, just read the salt from the database and reapply PBKDF2 to validate.

Everywhere I say "PBKDF2" here there are another options, probably the most common of which is scrypt (there is also bcrypt). The other options are technically better than PBKDF2. I don't think anyone would disagree with that. I usually recommend PBKDF2 because it's so ubiquitous and there's nothing really wrong with it. But if you have scrypt available, feel free to use that. The client and server do not have to use the same algorithm (the client can use PBKDF2 and the server can use scrypt if you like).



回答2:

What's the md5 hash of "superCommonPassword"? That's easy to pre-calculate.

It's b77755edafab848ffcb9580307e97414

If you steal a password database and see that hash value, you know the password is probably "superCommonPassword".

What's the md5 hash ("aStringYouDontKnowUntilYouStealAPasswordDatabase" + "superCommonPassword")? Oh, you can't calculate that until you steal the database.

An unknown salt means pre-calculating hashes of common passwords is useless. An unknown salt per user means you need to calculate hashes of common passwords for each user. This slows down the attacker and increases his costs.

Don't use md5 for password hashing though. Use bcrypt or scrypt or PBKDF2.