views:

779

answers:

9

I want to implement a salt into my login system but am a bit confused on how this is supposed to work. I can't understand the logic behind it. I understand md5 is a one-way algorithm and all of the functions that I have come across seem to hash everything together. If this is the case, how does one get the password back out for comparison? My biggest question is, how is salting a users' password safer than just hashing the password? If a database was ever to be compromised, the hash along with the salt is in the database. Isn't this all that a hacker would need?

I also found another post here on SO where another developer said :

"Ensure your salt and algorithm are stored separately from the database"

I would like to store the salt in the database. Is this really a problem if I do?

I'm looking for some help on understanding how this works and also what the best practice might be. Any help is greatly appreciated.


EDIT: I want to thank everyone for their responses and ideas. Even though I may be more confused now, it has certainly been a learning experience for me. Thanks again guys.

+4  A: 

You don't get the password out for comparison. You encrypt the password when they attempt a login and compare the stored value with the newly encrypted value.

brian
Yeah, because hashing a value is going to get the same hash every time, you simply compare the two hashes.
Chacha102
Ok, that much I get. I was doing this before but now that I want to use a salt, I don't understand. I guess what I am having a hard time understanding is how salting a password is any safer than not salting. The salt is in the database along side the hash. If a hacker had the database, how is this any safer?
Timmay
A better approach might be to inhibit dictionary attacks altogether. You can have a maximum login attempt count or increase the time between login attempts (e.g. by a power of n) by implementing a delay. This makes it very difficult to try more than a few passwords in a reasonable amount of time.
brian
@unknown: If you're talking about maximum login trials, you're looking at the wrong threat model. The right threat model is that a cracker has just downloaded your whole user/password table, and wants to crack as many passwords as they can.
Chris Jester-Young
@Chris any preventive approach in isolation is essentially useless. I wasn't suggesting it as an all-encompassing fool proof approach.
brian
@unknown: Perhaps. But all this talk about maximum trials is _completely orthogonal_ to the purpose of using salted password hashing (which is the OP's question); the former is aimed at online password guessing attacks, whereas the latter is aimed at offline cracking attacks.
Chris Jester-Young
+13  A: 

Forget about using salts (partly for the reason you mention), use bcrypt instead:

For a good explanation see: http://codahale.com/how-to-safely-store-a-password/

Rich
And the great thing about bcrypt? It contradicts silly assertions like storing the salt separately from the hash.... :-P (+1 for mentioning bcrypt; I 100% agree.)
Chris Jester-Young
lol.. I like the author's sense of humor. It is a great read. Thanks. :)
Timmay
Well, if bcrypt is a better way to go, then that's what I will use.
Timmay
@Timmay: Yes, bcrypt is the best way to go. Don't use MD5 or SHA1; that sort of advice is outdated by at least 20 years (so to speak). See: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
Chris Jester-Young
`bcrypt` is the best way to go until proven broken. Any hashing algorithm, by the pure definition of an hashing algorithm, means one input = one output. The speed doesn't give any security (who knows at what speeds we will be able to compute in a year). And if one computer isn't enough to brute-force your `bcrypt` hash, well I'll run my software on a freaking botnet to get the result. My point being that `bcrypt` isn't more secure than any salt+hash around.
Andrew Moore
Ok, so PHP's crypt extension can use Blowfish, but you still need to pass a 16 char salt - you're back where you started, no?
bdl
@Andrew: If it means your attacker has to employ 1000x more botnet nodes to crack the password, that just upped the ante quite a lot. (And the 1000x refers just to PHK's algorithm, which is 1000 iterations of MD5; bcrypt is even slower than that.)
Chris Jester-Young
From what I got from quickly reading through that link was that blowfish is ultra slow thereby making it harder and much longer to gain access to the password.
Timmay
@Timmay: Yes, exactly, and that's where the win is.
Chris Jester-Young
Thanks Chris. I'm all about logic and making something so slow seems to be the ticket. Do I need to install anything special or recompile PHP to use bcrypt?
Timmay
@Timmay: According to the link that Rich posted, this is a reasonable implementation of bcrypt in PHP (if below 5.3.0): http://www.openwall.com/phpass/ (They say that 5.3.0+ already have it builtin.)
Chris Jester-Young
Ah, cool. I am already on 5.3 so I guess it is already there then. :) At least **something** is tipping in my favor today.
Timmay
-1 bcrypt is a great tool for this job, but you should still be using salts (for reasons mentioned by Andrew) - the salt solves a different problem than the hash. The author of that article is wrong.
BlueRaja - Danny Pflughoeft
Where's NBcrypt?
Will
+13  A: 

An hash function always return the same value for the same input string. Let's say my user (Alice) has the password secret. Hashing secret using md5() leads to the following hash

5ebe2294ecd0e0f08eab7690d2a6ee69

Using a dictionary (a list of common words and password) or one of the various sites that offer you that service, the attacker (Mallory) can easily find out the password is secret when he sees in his dictionary that 5ebe2294ecd0e0f08eab7690d2a6ee69 = secret.

The process of salting before hashing makes it harder to use a dictionary attack without knowing your salt. Consider the following:

<?php
$salt = '@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!';
$hash = md5($salt . 'secret');

The resulting hash is now b58ad809eece17322de5024d79299f8a but Alice's password is still secret. Now if Mallory gets her hands on the salted hash, chances are she will not find the answer in her dictionary. If she does, the dictionary will give her the wrong answer.

Never store a static salt in your database. Preferably store it with your application's configuration (which by the way should not be available from the web).

If you are going to use a dynamic salt, you are going to need to use the database. Use a non-null column of existing valid data to build your salt on (blowfish-encrypted string of username based on a secret encryption key is usually cryptographically secure). Do not use a separate column for the salt. If you cannot use an existing column, incorporate your salt in the same column than your hash. For example, use the first 32 characters for your 128-bits salt and then the last 40 for your 160-bits hash. The following function will generate such an hash:

function seeded_sha1($string, $seed_bits) {
    if(($seed_bits % 8) != 0) {
        throw new Exception('bits must be divisible by 8');
    }

    $salt = '';
    for($i = 0; $i < $seed_bits; $i+=8) {
        $salt .= pack('c', mt_rand());
    }

    $hexsalt = unpack('h*hex', $salt);

    return $hexsalt['hex'] . sha1($salt . $string);
}

function compare_seeded_sha1($plain, $hash) {
    $sha1 = substr($hash, -40);
    $salt = pack('h*', substr($hash, 0, -40));

    $plain_hash = sha1($salt . $plain);
    return ($plain_hash == $sha1);
}

If an attacker gets in your database using SQL injection, at least the hashes he/she retrieves won't be useful since he/she won't have access to your application configuration. If your server gets rooted, it's pretty much game-over no matter what you do.

Note: There are other types of attack possible on md5() which is why you use more secure hashing algorithm, sha1() for example. Or, even better, use the Portable PHP password hashing framework, which has been designed with security in mind and is backwards compatible with pretty much any PHP version.

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}
Andrew Moore
Fantastic, explanation Andrew. Thanks. Don't go anywhere. I want to ask you a few questions after I finish reading the rest of your post.
Timmay
See http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html on why SHA-1 (or SHA-2, or anything else) is _not_ a "more secure hashing algorithm", for password hashing.
Chris Jester-Young
Ok, see, here is what is screwing me up... Everyone is saying to generate a **random salt** and store it in the database. Seems fair to me. But, what I am understanding from your post is that I should **not** store the hash in the database but instead, in the application. If I store the salt in the application, it fails to be dynamic at that point. Can you see my confusion?
Timmay
@Chris: The same approach could be taken with `bcrypt`. Dictionaries do exist for it as well. They are just less available. I'm sorry to say, dictionaries is a weakness that no hashing algorithm may solve.If I can't crack your `bcrypt` hash in enough time with one machine, I'll get a cluster. If it still isn't fast enough, I'll rent a bot net. And you don't know how fast we'll be able to hash a `bcrypt` hash in a year. Its supposed security through slowness is already broken I'm afraid.
Andrew Moore
@Andrew: No, security through slowness _is_ the best defence you have; you've got to slow down the brute force cracking as much as you can. If you say it's no defence, then that's equivalent to saying that any encryption is useless too, because people can brute-force it. :-P
Chris Jester-Young
@Timmay: having a dynamic salt will only slow-down your attacker. If you still want to have a dynamic salt, don't make it obvious to your attacker and use a field in your row that is NON-NULL to build your salt on. The worst thing you can do is have a field with seemingly random that or worst, a field called `salt`.
Andrew Moore
@Chris: The day an hashing function takes more than 2 seconds to compute, I'll consider it safe on that account. Till then, I can just parallelize my brute-forcing as much as I want to get the answer I want quickly.
Andrew Moore
I was working for the state making an application and had to use their computers and network. They had an extremely secure password algorithm to lock down passwords. No dictionary words, 2 uppercase letters 3 numbers, 16 characters that had to be changed every 20 days. I was running around the office looking for serial numbers off of the HP printers to use.
Timmay
@Andrew: You clearly haven't read up on bcrypt, then. bcrypt's win is that it's _tunable_. At the moment, if you use, say, 12 log-rounds, you can later up it to, say, 15 log-rounds. Each extra log-round doubles the amount of rounds used to compute a password trial. And I can bet you that right now, a 15-log-round salt will take _far longer_ than 2 seconds to try.
Chris Jester-Young
@Andrew. What is more secure? A random salt or a static salt? If you say static, then that is the way I will go. Would you recommend bcrypt?
Timmay
-1: Bad answer. The correct way to use a salt is to generate a random salt for each user and store it in the database. Trying to keep it separate or obscure the field name is amateurish nonsense. And using an artificially slow hash function is very much an accepted good practice.
Michael Borgwardt
@Timmay: Use a random salt. You will (marginally) increase security that way, for most algorithms. In the specific case of bcrypt, the number of log-rounds used is coded into the salt, so by using a different salt for each password, you can incrementally upgrade to stronger and stronger hashing.
Chris Jester-Young
@Michael: Edited my answer to what I meant originally. For dynamic salts, you do need to store it in the database, but don't add a field for it. Use an existing field of valid data, and encrypt it based on a static private secret key. That will yield a cryptographically secure hash.
Andrew Moore
@Michael. I don't claim to be an expert and is why I'm here but it seems to me that if I had a static key (salt) and I was the ONLY person in control of that salt then a hacker would not be able to crack the hashes. I mean, it seems logical to me anyway. Could you please explain how storing a random salt is safer than a static salt?
Timmay
@Timmay: If a the salt becomes known, it is easy to rebuild a dictionary as you only have one to build. Having a dynamic salt makes it harder as you need to build X dictionaries, one for every row.
Andrew Moore
@Timmay: The risk is that your attacker can access _all_ your site's code as well as _all_ the tables in the database. If you think of security from a "worst case scenario" point of view, then you've got everything covered (as well as possible, anyway).
Chris Jester-Young
@Andrew. What do you mean by store the dynamic salt in "an existing field of valid data"? Should I store the salt in with say, the email address or user name? Also... You are now talking about using a static private key. Is there a code snippet that I can look at so that maybe I can understand this a bit more? Admittedly, I'm more lost now than when I came in here. :)
Timmay
@Timmay: If you use bcrypt, the salt is stored with the hashed password. The library takes care of all that for you automatically.
Chris Jester-Young
@Chris Jester-Young you cannot use random salt, how yould you check for user password, if you didn't have last generated random salt?
Juraj Blahunka
@Timmay: No, but you can use, say, an encrypted version of the email address. That way, you are using existing data, but it is no apparent while looking at the table layout.
Andrew Moore
@Michael Borgwardt you don't have to generate unique salts for each user, just use already accessible columns as i pointed out in my answer http://stackoverflow.com/questions/2188507/help-with-salt-and-passwords/2188569#2188569
Juraj Blahunka
@juraj: The random salt is stored (in the clear) _with_ the hashed password. The salt doesn't really need to be kept secret, if it's unique per password.
Chris Jester-Young
@Andrew: Security by obscurity won't help you. Assume that your attacker can download a full copy of your source code, then decide if using "encrypted email address" is any better than just storing a random salt in the clear with your hashed password.
Chris Jester-Young
@Chris: As I stated, once you are rooted, it's pretty much game over. But having access to the source code, I can think of a bunch of easier way to get access to the password, with a quicker return than processing hashes. If the hash isn't apparent in the database, it will make it that much harder for an attacker with access to the database only.
Andrew Moore
@Chris: But why use another salt, if you already have persistent, not changing columns, which you can use as a salt with combination of a static salt?
Juraj Blahunka
@Andrew.. That makes complete sense to me as well.
Timmay
@Andrew: There are ways to obtain a web application's source code that doesn't involve getting full "game-over" root access, or even access to modify said code (which would, like you say, admit much easier attacks like logging all the passwords entered).
Chris Jester-Young
@Timmay: look at my answer for an explanation re "static key". @juraj: a generated salt has the advantage that you can ensure its length and quality more easily - and it prevents you from having to explain to the customer that it's impossible to change some fields because your *security concept* depends on them being fixed.
Michael Borgwardt
@Chris: if you have access to source code (root or any other type), it is pretty `totally` game over, from source code you can study all injections and breakdowns you can performs, that DB stays pretty unprotected :-)
Juraj Blahunka
@juraj: Wrong. Secure software does not depend on the secrecy of its source code for its security. Its security comes from being well-coded in the first place. You know, people can reverse-engineer all aspects of closed-source products; where do you think all the Microsoft security advisories come from? (Hint: IDA Pro.)
Chris Jester-Young
@chris: reverse engineering of a simple task like user login/logout, which is performed on the server side is pretty much impossible (as you said, if well coded).. hovewer getting user info, with help of compromised source code is much easier.. to sum up, I think, that this comment sections is pretty long and it starting to be controversial:-D
Juraj Blahunka
@Michael, I commented in your post below, asking you for your opinion on how you might go about locking down passwords if it were up to you. I'd like to leave here with something. :)
Timmay
-1 for *"Never store the salt in your database."* There is no reason not to store the salts in the database; however, they should be **unique for each user** or it is useless. And of course, there is no problem with using a unique database-field for the salts either, since **the salt is not considered a secret**.
BlueRaja - Danny Pflughoeft
@BlueRaja: You obviously stop reading in the middle of the post. And while the salt is not considered a secret, if only your database is compromised, basing your salt on an existing field will considerably hamper the ability of an attacker to be able to gain access to a particular account. If the salt is clear in the database and the attacker is only interested in one particular account, it is considerably easier for him to build a dictionary to try and find the password (if that said password is not secure).
Andrew Moore
*"basing your salt on an existing field will considerably hamper the ability of an attacker to be able to gain access to a particular account"* - now why in the world would you think that? I hope you're not going to argue that it's "security by obscurity"? :)
BlueRaja - Danny Pflughoeft
@BlueRaja: Lets assume that the attacker has access to only your database. If you base your salt on a blowfish-encrypted version of your email address (for example), the attacker as absolutely no way of finding out the salt and cannot build a dictionary for a particular account. He doesn't have your key, and he doesn't even have the encryption method used. Simply using a field as it is doesn't have any value since its "security by obscurity", but applying an operation to it (such as encryption) does prevent an attacker with only DB access from doing anything with your hashes.
Andrew Moore
Chris Jester-Young has been correct on every point so far.
Steven Sudit
Amazing discussion, and *very* informing. Thanks everyone. And there should be a SO badge for having the *very first question* skyrocket this far. :)
Pekka
@Chris: That's beside the point. People reverse-engineer because they have access to the binaries. When you don't have access to neither the source nor the binaries, you'll agree that reverse-engineering gets a lot harder (not impossible, harder).
Andrew Moore
-1 for "Use a non-null column of existing valid data to build your salt on". This would tie the encrypted password to some other data, which is bad. Use a secure random number generator to generate the salt for each password. Or use a library that does salting and hashing for you and store all its data including salt as the hashed password.
starblue
Last code-example is copied from: http://stackoverflow.com/questions/1581610/help-me-make-my-password-storage-safe/1581919#1581919
Jacco
@Jacco: Last code example is copied from the PHP Password Hashing Documentation. Please get your references straight.
Andrew Moore
@Andrew Moore: then please link to the URL containing this code-example and I will stand corrected. (Google can't find it and I can clearly remember writing exactly this example.)
Jacco
@Jacco: See `test.php` from the 0.1 distribution of phppass.
Andrew Moore
@Andrew Moore: All revisions of `test.php` are here: http://cvsweb.openwall.com/cgi/cvsweb.cgi/projects/phpass/ The code-block is not in there. So I stand by my original claim.
Jacco
+1  A: 

Salting a user's password is possibly safer than just hashing the password because it can protect against precomputation attacks.

For instance, if a hacker gets access to your database, and the passwords are not salted, then he can look up the hashes in his database of hashes (see http://en.wikipedia.org/wiki/Rainbow_table) to get the original passwords.

Sam
+2  A: 

As you mentioned, hashing algorithms work only one-way (or only if they are strong enough :-D)

For your question about salting I would recommend to hash a password with a static salt string and some dynamic data from database, which should not change after once created

This is a very secure way of storing passwords, as even if database is compromised, hackers/crackers still need to get your static string hash and need to guess how you applied all the salting..

For example let's say you have a users table with these columns:

id
username
password
created_at

columns id and created_at after once filled should never be changed..

so when you are hashing user's password you can do as simple as:

<?php
    $staticSalt = '!241@kadl;ap][';
    $userPass = 'my new pass';
    // assuming $user variable is already populated with DB data
    // we will generate new hash from columns and static salt:
    $genPass = sha1($user['id'] . $userPass . $user['created_at'] . $staticSalt);
?>

I hope this one helps :) cheers

Juraj Blahunka
+15  A: 

The point of a salt is to prevent attackers from amortizing the cost of a brute force attack across sites (or better yet, when using a different salt for each user: all users of a site) through precomputed rainbow tables.

With plain hashing, an attacker can compute such a table once (a very long, costly operation) and then use it to quickly find passwords for any site. When a site uses one fixed salt, the attacker has to compute a new table specifically for that site. When a site uses a different salt for each user, the attacker can stop bothering with rainbow tables - he'll have to brute-force each single password separately.

Storing the salts separately is not necessary to gain this advantage. In theory it would be even more secure because it would neutralize the weakness of dictionary or short passwords. In practice, it's not worth bothering with because at the end of the day, you need access to the salts somewhere to check passwords. Also, trying to separate them would lead to more complex systems - and the more complex a system is, the more opportunities for security holes there are.

Edit: My concrete recommendations:

  • Generate long pseudorandom salt for each user and store in in the DB
  • Use a bcrypt-based hash
  • ideally, don't implement it yourself, use an existing library instead
Michael Borgwardt
Thanks Mike. So, it's like 6 to 1, half a dozen to another... If it were you, how would you do this? What is the best practice in your own mind?
Timmay
Thanks Michael. I'm sure your probably tired of this thread by now but would you mind answering a couple more questions? I'm on 5.3 currently and crypt is part of the distro. When you say use an existing lib, is using PHPs crypt function ok or not?
Timmay
+1 great final advice. @Timmay This deserves the big green checkmark :)
BlueRaja - Danny Pflughoeft
@Timmay: It's OK but the phpass library I linked to would be even better. It would probably save you some work and has automatic fallbacks that will be used when the system has to run on an older PHP version.
Michael Borgwardt
Exactly as Michael Borgwardt said and this cannot be understated seen the level of misinformation in many answers. Michael is right on spot: "storing salts separately is not necessary to gain this advantage". The whole point of salts is to prevent rainbow tables attack. A salt, even in the clear, pefectly serves that purpose.
Webinator
+4  A: 

The other answers are good, so I'll just throw in a minor point that nobody else has mentioned. You don't want to use the same salt for every password because then if two people have the same password, they'll have the same hash. That's exposing information that an attacker can exploit.

You could use the same salt for every user along with Juraj's good idea to combine the password with other non-changing database fields (unique to a user). But watch out because this information gets tied to the password. If you were to hash the username + password together to guarantee a unique hash, you wouldn't be able to change the username without creating a new user and requiring them to set a new password.

As an example of having a unique salt per user and storing it alongside the password hash, I'll point out /etc/shadow on your typical Linux system.

root@linux:/root# cat /etc/shadow | grep root
root:$1$oL5TTZxL$RhfGUZSbFwQN6jnX5D.Ck/:12139:0:99999:7:::

Here, the oL5TTZxL is the salt and RhfGUZSbFwQN6jnX5D.Ck/ is the hash. The plain-text password is root in this case, and the hash algorithm my system uses is the MD5-based BSD password algorithm. (newer systems than mine have better hash algorithms)

indiv
Indiv, thanks.. That make perfect sense. So I really need to think about what I want to hash. What about hashing the users' password along with a static key that only I know? A key that resides in my application?
Timmay
A static key would provide an additional level of obfuscation, but it's proper when evaluating security to assume that an attacker has all knowledge of your system, including source code. In this case, your static key is just a static salt, and doesn't significantly increase the security of your system.
indiv
And I think it should be pointed out that Linux's security track record could be considered quite good and they are obviously storing the salt in the clear in the 'DB'. The whole point of salt is to prevent rainbow tables attack. Note brute force attacks. Having a salt in the clear is not an issue at all because it fully full fills its purpose: defeating rainbow tables attack. Storing a salt in the clear is not only common but normal: it doesn't make your security more vulnerable to a brute force attack. Saying that the salt shouldn't be stored in the clear is silly.
Webinator
+2  A: 

Hashing passwords is meant to keep those passwords secret from your own administrator(s).

1) Keeping plain text passwords in your database would be fine except your passwords may be used by the administrator to gain access to some other system.

2) You can use a single global salt, which is combined with the passwords (by prepending or XORing them) and then hashing for storage in the database. But that is vulnerable to a malicious administrator AND a rainbow table designed for that one salt.

3) You can have a separate salt for each user: The database will be used to store the salt, and the hash derived from the password/salt combination. This will prevent a rainbow attack, but brute force attacks will still be possible.

4) Finally, you can keep your hash function a secret by using a velocity-limited hardware hashing solution.

That is as good as you can do. Because of human nature, passwords have a limited domain and are vulnerable to brute force attacks. We are trying to prevent administrators getting a hold of user passwords, and then using them on other systems they should not have access to.

Some other notes:

a) You can use bcrypt on the password/salt combination to slow down the attacker’s brute force attack. But since we are assuming administrators, they can be patient.

b) Keeping the salt separate from the password hash is not an effective defense, we are assuming administrators after all.

c) Using existing data as a salt is a little better, but I doubt existing data has as much entropy a random salt has.

Kyle Lahnakoski
Thanks Kyle.. I'm still here trying to figure out how to use bcrypt. Have you used it before as part of PHPs distro?
Timmay
The "administrator" could also be someone who has found a SQL-injection hole in your site and has dumped out your DB schema and the contents of your user table.
geofftnz
Good point about the administrators. I'm proud to say that even I, as the designer of our password system, could not figure out any user's password without a brute force attack. If I can't do it, how is someone with less knowledge about the system going to?
A: 

Some of these posts are shockingly bad.

SHA1 is not 20 years out of date. It was invented in 1993. It is considered vulnerable, but no exploits are known for it. If you are concerned, you can start using SHA256, which has no known vulnerabilities.

Don't use bcrypt. The argument that bcrypt is "slow" and therefore more secure makes no sense. Bcrypt can be defeated with rainbow tables. Also, what if somebody invents a blowfish coprocessor someday? This is simply a kind of security-through-obscurity method.

Read FIPS 180-1 Secure Hash Standard. SHA1 is approved, and bcrypt is not. You think the NSA is using bcrypt?! Hell no, hey are using SHA2 with large digests. (Or maybe even an unnannounced SHA3?)

The only way to deter brute-force offline attacks is to require complex passwords. If you randomly select a password with upper case, lower case, numeric, and special characters that is 10 characters long, then the brute-force method will require on average 10^82/2 checks to break your password. That's a pretty large number. Larger than the time elapsed since the big bang (measured in femtoseconds), larger than the number of particles in the universe, etc.

Nobody is cracking that with any kind of GPU.

Somebody clever came up with the idea of Rainbow tables. It lets you precompute all of the hashes for a particular password space (e.g. all 8 character alphanumeric passwords) and then store it in a relatively compact format (the size of a DVD, say) that still allows you to search it very easily. This precompute step only has to be done once (maybe it takes several weeks with a large CPU cluster) for any password space. But once it's done, you can use it to quickly crack passwords over and over. It's a space-time tradeoff.

However, rainbow tables become unwieldy if the password space is not 8 characters, but is actually, say... 40. Now it would take years to build the rainbow table and a bookshelf of DVDs to store it.

This is why you add random salts to each user. Sure, somebody can still brute force a single weak password, but they can't use a rainbow table because the rainbow table contains precomputed hashes that do not include your salt.

mehaase