24

I don't like this idea. But I can not come up with a technical argument against it. Can somebody explain it to me? The basic idea is:

$passwd = 'foo';
$salt = hash($passwd);
$finalHash = hash($passwd . $salt);

The $finalHash is what would be stored in the database. I do understand that two users with the same password "foo" would have identical hashes. But that is only one weakness of this plan. And such collisions, while dangerous, are not the primary reason we use salts with hashes. But so far this the only technical objection I have come up with to argue against this.

My understanding is that salts should be random and should be unique for each use of the hash. And this scheme appears to violate both requirements. But I can't figure out how an attacker could benefit from this seemingly flawed use of salted hashing.

joe user
  • 243
  • 2
  • 4
  • Really, just use [bcrypt](http://en.wikipedia.org/wiki/Bcrypt). There is a version for whatever language you're using. – Stephen Touset Apr 01 '13 at 01:14
  • 8
    "And such collisions, while dangerous, are not the primary reason we use salts with hashes." Actually, yes they are. – Ilmari Karonen Apr 01 '13 at 09:41
  • Actually, even i do not understand that why this is bad. As i saw few of other answers they say that if someone breaks into your database then they can easily break the hashes but what i think is that even if we use random salt each time then we have to store them with our hashed password for comparison and if someone breaks into the database then he will also get the salt used for hashing. In that case also the attacker can break the hashes as he knows the salt used for each password. – Chirayu Chiripal Apr 01 '13 at 14:52
  • @ChirayuChiripal: You are correct that if the attacker has the salt and the hash then they can try to determine the password that produced that salted hash. That's not the point. The point of the random salt is so that the attacker cannot start the attack on the hash *before they obtain the database*. If the password hashes are not salted randomly then the attacker can spend hours, days, weeks, *years*, computing the unsalted hashes of billions of possible passwords, in preparation for the day that they manage to get the database. That day they would then have no work to do. – Eric Lippert Apr 01 '13 at 17:02
  • 6
    @EricLippert The point of the random salt is actually so that the attacker cannot use the results of an attempt on *one* password to gain information about *all* passwords. With the approach in the question, an attacker only has to hash `pass123` once to learn if any users have that password. With unique salts, they would have to hash `pass123` for *every* user before being able to move to the next guess. As a counterpoint, a constant site-wide salt stored in the database thwarts your concerns with precomputation, but does nothing to prevent what I've described. – Stephen Touset Apr 01 '13 at 18:26
  • Although not advisable, you could use the username as salt. This way you have a unique salt for every password hash. But I suppose a lot of hackers try this method when they try to crack a password database – BlueCacti Apr 22 '14 at 21:07
  • @IlmariKaronen Bruteforce resistance could be considered the 'Primary' and hash collisions a close 'Secondary'. – Andrew Hoffman Jun 23 '14 at 17:42

5 Answers5

27

To answer this, one has to understand why salts are needed in the first place. This is explained pretty well in How to securely hash passwords?; here's an excerpt from the accepted answer:


Salts: among the advantages of the attacker over the defender, is parallelism. The attacker usually grabs a whole list of hashed passwords, and is interested in breaking as many of them as possible. He may try to attack several in parallels. For instance, the attacker may consider one potential password, hash it, and then compare the value with 100 hashed passwords; this means that the attacker shares the cost of hashing over several attacked passwords. A similar optimisation is precomputed tables, including rainbow tables; this is still parallelism, with a space-time change of coordinates.

The common characteristic of all attacks which use parallelism is that they work over several passwords which were processed with the exact same hash function. Salting is about using not one hash function, but a lot of distinct hash functions; ideally, each instance of password hashing should use its own hash function. A salt is a way to select a specific hash function among a big family of hash functions. Properly applied salts will completely thwart parallel attacks (including rainbow tables).


So the problem of your salt is that it doesn't interfere with parallelizing breaking the hashes, which is the very purpose of salting. I strongly recommend you to read the original answer, it has further advice on salting.

Shnatsel
  • 2,802
  • 2
  • 16
  • 15
  • 1
    Based on reading that, I do see that the problem with my example is that the salt is not guaranteed to be unique. But I still don't understand *how* an attacker could exploit this lack of randomness (besides the collision of two users with the same password). – joe user Mar 31 '13 at 20:51
  • 2
    @joeuser Let's say you have a database with N hashed passwords that gets stolen. Using your scheme, each guess the attacker makes has to be hashed twice, then it can be compared against all N (which is usually trivial compared to the cost of hashing). With unique salts, the attacker would have to perform N hash operations to see if the guess is correct for anything. The attacker also wouldn't realistically be able to pre-compute any hashes as part of a rainbow table attack (assuming a reasonable sized hash), while yours does nothing to thwart a rainbow table attack. – Kitsune Mar 31 '13 at 21:19
  • 10
    To simplify @Kitsune's example, assume I'm brute-forcing my way through your password database. If I compute the hash for `pass123`, I know immediately if *any* of your users have that password, even if it's only one of them. On the other hand, if you were using unique salts, I would have to hash `pass123` for *every one* of your users. – Stephen Touset Apr 01 '13 at 02:53
25

If you use the password as "salt" then you are not using any salt at all; you are just hashing the password.

If two users choose the same password, they end up with the same hashed password. That's what is often told as if it explained the problem, but it seems that most people get it wrong. They imagine that this means "collision", which, for some reason, is considered by many to be a bad word when talking about password hashing. But that's wrong, and not the point.

The point is determinism. Suppose that I, wantonly, grab a copy of the hashed passwords for 1000 users (e.g. I retrieved an old backup tape from your garbage bin). Then I can "try" potential passwords: I hash a potential password (using the password itself as "salt") and then I look up the value among the 1000 hashed values. This means that by paying the computational price of one hashing, I actually try one thousand user+password pairs. I am attacking one thousand of hashed passwords in parallel, for the same cost as attacking a single one. This kind of parallelism can express itself under several guises, including rainbow tables.

We really prefer it when attacking 1000 hashed passwords costs 1000 times the cost of attacking 1 hashed password. To do that, you need real salts, i.e. salts which are distinct for distinct users, even when they happen to use the same password -- and, actually, when they potentially use the same password. When there is no real salt, the parallel attack works not because some users do choose the same password, but because if they had chosen the same password then they would have obtained the same hashed value. They don't actually need to choose the same password to trigger the weakness.

Using the user name as salt is much better. It is not good, mind you; but still better. What is even better, to the point of being actually decently secure, is to use random salts.

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
16

If two users have the same password, then the salt will be the same, resulting in the same hash for both. This is undesirable, because it leaks information about passwords. If Alice breaks into your database and sees that Bob has the same hash as her, she can use that information. Pick something that is guaranteed to be unique.

Your biggest problem here, though, is that you're using hash without any information about what that hash is. Depending on the system, it might even be the old crappy 3DES implementation that strips everything after the 8th character. You should be using a proper KDF such as bcrypt or PBKDF2.

Polynomial
  • 132,208
  • 43
  • 298
  • 379
  • In the psuedocode I wrote, hash() represents any hashing algorithm. But I do plan to require some modern algorithm when we finally implement this. – joe user Mar 31 '13 at 20:48
  • 2
    If it was 3DES is would be dropping everything after the 24th character, which would be better; but, alas, the traditional Unix "crypt()" password hashing function is based on a modified DES, not 3DES.\ – Thomas Pornin Mar 31 '13 at 20:59
  • @ThomasPornin My bad, that's correct. – Polynomial Mar 31 '13 at 21:03
0

Using a username or password as a salt doesn't sound like a good idea to me.

An attacker might reasonably guess that you're using the username or password as the salt. Depending on your setup it might be very reasonable to assume an attacker could gain access to usernames.

Also depending on how strict your system is at enforcing passwords the attacker could take advantage of passwords that appear in a dictionary of known/common passwords, and as these are used as the salt your system would be vulnerable to this kind of attack.

Using a salt that doesn't rely on user input is a much better idea.

Drew Khoury
  • 441
  • 3
  • 10
  • Doesn't matter too much if the attacker knows the salt, as long as every password has a different salt. The salting makes sure that the attacker has to attack one user at a time, instead of a parallel attack against the whole database. – gnasher729 Jun 23 '14 at 15:17
0

There have been cases recently where more than 100,000,000 hashes have been leaked. Hopefully they were salted. I think a big number like this makes the effect of salting much more obvious.

Let's say there are passwords that are not really unsafe, but not quite secure enough, because the chance that a random user uses one of these passwords is one in 10 billion. If I try just 100 such passwords, then I can expect to guess the password of one of these 100 million people. Since the password was hashed, then salted with the hash and hashed again, I can easily figure out what is stored in the database for each of these passwords, so after 100 hashes I found a password.

If the passwords were properly salted, each with a different salt, even if each salt is known, I have to calculate 10 billion hashes to get the same result.

gnasher729
  • 1,823
  • 10
  • 14
  • What hash dump contained 100 million passwords? LinkedIn was the largest I can think of a 6.5 million. There's only a handful of sites with 100 million users, and that'd be a big deal... – David Jun 23 '14 at 15:43
  • @David Last estimate I saw for the Adobe final tally was 150 million, and Ebay was at least 145 million, though if they're playing fast and loose with their press release wording (as some suspect) and inactive accounts were affected as well, it could be in the multiple hundreds of millions. – Xander Jul 18 '14 at 23:40