I know there are tons of blogs, articles, and questions on SO about salting passwords, but one thing I haven't been able to find an answer to is this:
If I am generating a password hash like this:
$salt = randomString
$password = $_POST['password']
hashedPassword = sha1($password.$salt)
And I have a table like this:
Users
user_id | hashedPassword | salt
Why is it so difficult for an attacker to figure this password out? Can't they just use a rainbow table, or brute force to figure out the salt, and then append the salt to every word in a dictionary attack?
Can't they just use a rainbow table,
or brute force to figure out the salt,
How would that work? But it's a non-issue anyway -
assume that the attacker knows the salt. Its purpose is not to be secret, that's why you store it right next to the hash.
and then append the salt to every word
in a dictionary attack?
Sure they can do that, but they have to do it for that particular user. They cannot amortize the effort over all users in the DB, or use a precomputed table of hash->password mappings.
That, and only that is the point of a salt.
They can do that. The power is that they would therefore need to generate a new rainbow table for each password (or iterate through each dictionary entry for each password).
So the total compute time for a single password is still the same as for a common salt. But the total compute time for multiple passwords goes up exponentially...
Oh, and it's typically considered good practice to have two salts. One stored in the database that's unique per password hash, and one stored on the filesystem that's unique for the whole site. That way if the database is compromised, there's no significant worry as they only have 1/2 the salts used. Sure, if the filesystem's compromised they could get it all, but if the filesystem's compromised, they can install password sniffers and other nasties...
I hope that helps...
Well, for one they cannot use a precomputed rainbow table to find a collision - an attacker would have to generate their own rainbow table using the salt. Also, assuming every user has a different salt, that rainbow table would only work for a single user - making their job that much more difficult.
The point of the salt is not to make a single password stronger. It is about preventing the attacker from scaling up, when attacking several passwords. With the salt, the attacker cannot reuse his efforts into attacking another password; he must rehash his dictionary.
Rainbow tables are nothing magical; they are just a special case of a precomputed table, which is akin to a simple dictionary attack with slightly distinct space-time modalities. Building the rainbow table implies more or less going through the complete dictionary. Precomputed tables are a gain for the attacker if he can use them to attack several passwords. If passwords are salted, then precomputed tables, rainbow or not, will not gain him anything.
That being said, a single password is often weak and can be brute-forced, because the average password will fit in the average user brain, and, as such, cannot be very complex. To mitigate that risk, one should use repeated or iterated hashing. A salt does not help here (but it does not harm either). See this answer for details.
Let's use a simple example: we have two databases, Alpha and Beta:
Alpha just hashes the password and stores the result:
row: {
passwordHash = Hash(password)
}
Beta creates a random value for each user and uses it as part of the input to the hash function:
row: {
salt = RandomString(),
passwordHash = Hash(password + salt)
}
Now say your adversary has prior knowledge that some of your users are using the password: "password"
To find all users in Alpha whose password is "password", you only have to calculate the hash of "password" once. Here's an example from SQL:
DECLARE #Hash INT; SET #Hash = Hash("password");
SELECT UserID FROM Users WHERE passwordHash = #Hash
Since it just involves integer equality, it's about as efficient as a query can be. Even if Alpha had hundreds of thousands of users, it would return very quickly.
The fact that Beta's hashes include a row-specific random value in every password hash, you cannot write a similarly efficient query for it. The closest you could get would be to re-evaluate the (intentionally expensive to compute) hash function for every row's salt:
SELECT u.UserID FROM Users u WHERE u.passwordHash = Hash("password" + u.salt)
The fact that searching for a known password is so expensive should indicate how expensive it is to perform a brute force attack, even if that attack is guided by dictionaries of common passwords, or algorithms that attempt to mix words and numbers together to create passwords the way humans do.
You already know that salt is a measure to defend against "rainbow table" attacks, so your question is... how?
"Rainbow table" has become a flowery term for any attack that computes the hashes for common and likely potential passwords ahead of time and stores them in an efficient lookup table. Once you have that table built (which can take several hours), you then iterate through every User and see if their password hash is in the lookup table. If it is, you'll have guessed that user's password.
The users within Alpha are indeed vulnerable to this kind of attack. Alpha will have equivalent hashes for equivalent passwords, so a hash table or rainbow table could be used to reverse the hashes. But Beta cleverly sidesteps this vulnerability by making the result of the hash function unique to the user by virtue of the salt.
I hope this helps some reader, someday!
Related
I'm having some trouble understanding the purpose of a salt to a password. It's my understanding that the primary use is to hamper a rainbow table attack. However, the methods I've seen to implement this don't seem to really make the problem harder.
I've seen many tutorials suggesting that the salt be used as the following:
$hash = md5($salt.$password)
The reasoning being that the hash now maps not to the original password, but a combination of the password and the salt. But say $salt=foo and $password=bar and $hash=3858f62230ac3c915f300c664312c63f. Now somebody with a rainbow table could reverse the hash and come up with the input "foobar". They could then try all combinations of passwords (f, fo, foo, ... oobar, obar, bar, ar, ar). It might take a few more milliseconds to get the password, but not much else.
The other use I've seen is on my linux system. In the /etc/shadow the hashed passwords are actually stored with the salt. For example, a salt of "foo" and password of "bar" would hash to this: $1$foo$te5SBM.7C25fFDu6bIRbX1. If a hacker somehow were able to get his hands on this file, I don't see what purpose the salt serves, since the reverse hash of te5SBM.7C25fFDu6bIRbX is known to contain "foo".
Thanks for any light anybody can shed on this.
EDIT: Thanks for the help. To summarize what I understand, the salt makes the hashed password more complex, thus making it much less likely to exist in a precomputed rainbow table. What I misunderstood before was that I was assuming a rainbow table existed for ALL hashes.
A public salt will not make dictionary attacks harder when cracking a single password. As you've pointed out, the attacker has access to both the hashed password and the salt, so when running the dictionary attack, she can simply use the known salt when attempting to crack the password.
A public salt does two things: makes it more time-consuming to crack a large list of passwords, and makes it infeasible to use a rainbow table.
To understand the first one, imagine a single password file that contains hundreds of usernames and passwords. Without a salt, I could compute "md5(attempt[0])", and then scan through the file to see if that hash shows up anywhere. If salts are present, then I have to compute "md5(salt[a] . attempt[0])", compare against entry A, then "md5(salt[b] . attempt[0])", compare against entry B, etc. Now I have n times as much work to do, where n is the number of usernames and passwords contained in the file.
To understand the second one, you have to understand what a rainbow table is. A rainbow table is a large list of pre-computed hashes for commonly-used passwords. Imagine again the password file without salts. All I have to do is go through each line of the file, pull out the hashed password, and look it up in the rainbow table. I never have to compute a single hash. If the look-up is considerably faster than the hash function (which it probably is), this will considerably speed up cracking the file.
But if the password file is salted, then the rainbow table would have to contain "salt . password" pre-hashed. If the salt is sufficiently random, this is very unlikely. I'll probably have things like "hello" and "foobar" and "qwerty" in my list of commonly-used, pre-hashed passwords (the rainbow table), but I'm not going to have things like "jX95psDZhello" or "LPgB0sdgxfoobar" or "dZVUABJtqwerty" pre-computed. That would make the rainbow table prohibitively large.
So, the salt reduces the attacker back to one-computation-per-row-per-attempt, which, when coupled with a sufficiently long, sufficiently random password, is (generally speaking) uncrackable.
The other answers don't seem to address your misunderstandings of the topic, so here goes:
Two different uses of salt
I've seen many tutorials suggesting that the salt be used as the following:
$hash = md5($salt.$password)
[...]
The other use I've seen is on my linux system. In the /etc/shadow the hashed passwords are actually stored with the salt.
You always have to store the salt with the password, because in order to validate what the user entered against your password database, you have to combine the input with the salt, hash it and compare it to the stored hash.
Security of the hash
Now somebody with a rainbow table could reverse the hash and come up with the input "foobar".
[...]
since the reverse hash of te5SBM.7C25fFDu6bIRbX is known to contain "foo".
It is not possible to reverse the hash as such (in theory, at least). The hash of "foo" and the hash of "saltfoo" have nothing in common. Changing even one bit in the input of a cryptographic hash function should completely change the output.
This means you cannot build a rainbow table with the common passwords and then later "update" it with some salt. You have to take the salt into account from the beginning.
This is the whole reason for why you need a rainbow table in the first place. Because you cannot get to the password from the hash, you precompute all the hashes of the most likely used passwords and then compare your hashes with their hashes.
Quality of the salt
But say $salt=foo
"foo" would be an extremely poor choice of salt. Normally you would use a random value, encoded in ASCII.
Also, each password has it's own salt, different (hopefully) from all other salts on the system. This means, that the attacker has to attack each password individually instead of having the hope that one of the hashes matches one of the values in her database.
The attack
If a hacker somehow were able to get his hands on this file, I don't see what purpose the salt serves,
A rainbow table attack always needs /etc/passwd (or whatever password database is used), or else how would you compare the hashes in the rainbow table to the hashes of the actual passwords?
As for the purpose: let's say the attacker wants to build a rainbow table for 100,000 commonly used english words and typical passwords (think "secret"). Without salt she would have to precompute 100,000 hashes. Even with the traditional UNIX salt of 2 characters (each is one of 64 choices: [a–zA–Z0–9./]) she would have to compute and store 4,096,000,000 hashes... quite an improvement.
The idea with the salt is to make it much harder to guess with brute-force than a normal character-based password. Rainbow tables are often built with a special character set in mind, and don't always include all possible combinations (though they can).
So a good salt value would be a random 128-bit or longer integer. This is what makes rainbow-table attacks fail. By using a different salt value for each stored password, you also ensure that a rainbow table built for one particular salt value (as could be the case if you're a popular system with a single salt value) does not give you access to all passwords at once.
Yet another great question, with many very thoughtful answers -- +1 to SO!
One small point that I haven't seen mentioned explicitly is that, by adding a random salt to each password, you're virtually guaranteeing that two users who happened to choose the same password will produce different hashes.
Why is this important?
Imagine the password database at a large software company in the northwest US. Suppose it contains 30,000 entries, of which 500 have the password bluescreen. Suppose further that a hacker manages to obtain this password, say by reading it in an email from the user to the IT department. If the passwords are unsalted, the hacker can find the hashed value in the database, then simply pattern-match it to gain access to the other 499 accounts.
Salting the passwords ensures that each of the 500 accounts has a unique (salt+password), generating a different hash for each of them, and thereby reducing the breach to a single account. And let's hope, against all probability, that any user naive enough to write a plaintext password in an email message doesn't have access to the undocumented API for the next OS.
I was searching for a good method to apply salts and found this excelent article with sample code:
http://crackstation.net/hashing-security.htm
The author recomends using random salts per user, so that gaining access to a salt won't render the entire list of hashes as easy to crack.
To Store a Password:
Generate a long random salt using a CSPRNG.
Prepend the salt to the password and hash it with a standard
cryptographic hash function such as SHA256.
Save both the salt and the hash in the user's database record.
To Validate a Password :
Retrieve the user's salt and hash from the database.
Prepend the salt to the given password and hash it using the same hash function.
Compare the hash of the given password with the hash from the database. If they
match, the password is correct. Otherwise, the password is incorrect.
The reason a salt can make a rainbow-table attack fail is that for n-bits of salt, the rainbow table has to be 2^n times larger than the table size without the salt.
Your example of using 'foo' as a salt could make the rainbow-table 16 million times larger.
Given Carl's example of a 128-bit salt, this makes the table 2^128 times larger - now that's big - or put another way, how long before someone has portable storage that big?
Most methods of breaking hash based encryption rely on brute force attacks. A rainbow attack is essentially a more efficient dictionary attack, it's designed to use the low cost of digital storage to enable creation of a map of a substantial subset of possible passwords to hashes, and facilitate the reverse mapping. This sort of attack works because many passwords tend to be either fairly short or use one of a few patterns of word based formats.
Such attacks are ineffective in the case where passwords contain many more characters and do not conform to common word based formats. A user with a strong password to start with won't be vulnerable to this style of attack. Unfortunately, many people do not pick good passwords. But there's a compromise, you can improve a user's password by adding random junk to it. So now, instead of "hunter2" their password could become effectively "hunter2908!fld2R75{R7/;508PEzoz^U430", which is a much stronger password. However, because you now have to store this additional password component this reduces the effectiveness of the stronger composite password. As it turns out, there's still a net benefit to such a scheme since now each password, even the weak ones, are no longer vulnerable to the same pre-computed hash / rainbow table. Instead, each password hash entry is vulnerable only to a unique hash table.
Say you have a site which has weak password strength requirements. If you use no password salt at all your hashes are vulnerable to pre-computed hash tables, someone with access to your hashes would thus have access to the passwords for a large percentage of your users (however many used vulnerable passwords, which would be a substantial percentage). If you use a constant password salt then pre-computed hash tables are no longer valuable, so someone would have to spend the time to compute a custom hash table for that salt, they could do so incrementally though, computing tables which cover ever greater permutations of the problem space. The most vulnerable passwords (e.g. simple word based passwords, very short alphanumeric passwords) would be cracked in hours or days, less vulnerable passwords would be cracked after a few weeks or months. As time goes on an attacker would gain access to passwords for an ever growing percentage of your users. If you use a unique salt for every password then it would take days or months to gain access to each one of those vulnerable passwords.
As you can see, when you step up from no salt to a constant salt to a unique salt you impose a several orders of magnitude increase in effort to crack vulnerable passwords at each step. Without a salt the weakest of your users' passwords are trivially accessible, with a constant salt those weak passwords are accessible to a determined attacker, with a unique salt the cost of accessing passwords is raised so high that only the most determined attacker could gain access to a tiny subset of vulnerable passwords, and then only at great expense.
Which is precisely the situation to be in. You can never fully protect users from poor password choice, but you can raise the cost of compromising your users' passwords to a level that makes compromising even one user's password prohibitively expensive.
One purpose of salting is to defeat precomputed hash tables. If someone has a list of millions of pre-computed hashes, they aren't going to be able to look up $1$foo$te5SBM.7C25fFDu6bIRbX1 in their table even though they know the hash and the salt. They'll still have to brute force it.
Another purpose, as Carl S mentions is to make brute forcing a list of hashes more expensive. (give them all different salts)
Both of these objectives are still accomplished even if the salts are public.
As far as I know, the salt is intended to make dictionary attacks harder.
It's a known fact that many people will use common words for passwords instead of seemingly random strings.
So, a hacker could use this to his advantage instead of using just brute force. He will not look for passwords like aaa, aab, aac... but instead use words and common passwords (like lord of the rings names! ;) )
So if my password is Legolas a hacker could try that and guess it with a "few" tries. However if we salt the password and it becomes fooLegolas the hash will be different, so the dictionary attack will be unsuccessful.
Hope that helps!
I assume that you are using PHP --- md5() function, and $ preceded variables --- then, you can try looking this article Shadow Password HOWTO Specially the 11th paragraph.
Also, you are afraid of using message digest algorithms, you can try real cipher algorithms, such as the ones provided by the mcrypt module, or more stronger message digest algorithms, such as the ones that provide the mhash module (sha1, sha256, and others).
I think that stronger message digest algorithm are a must. It's known that MD5 and SHA1 are having collision problems.
I've asked myself this question a dozen of times.
Is a password salt really necessary?
I couldn't find any good literature on the subject.
From a security perspective, do password salts help?
If a database is breached, isn't the salt lost if the password is anyways?
Also, from a brush force perspective, if i ban IP's is there really any reason to store salts?
Yes, you should always use salts. fortunately PHP is pretty clever. From this article:
If you use the default options for the password_hash() function PHP will generate a random salt for each password as it is hashed. The random salt is an additional layer of security which makes it exceptionally hard to crack any passwords. Even if two or more users use the same password each of their hashes will be different.
This gets you away from having to generate a salt and leaves the heavy lifting up to PHP. The verification piece, password_verify(), uses the random salt placed in the hash to be able to test against a given password.
From the docs for password_verify():
Note that password_hash() returns the algorithm, cost and salt as part of the returned hash. Therefore, all information that's needed to verify the hash is included in it. This allows the verify function to verify the hash without needing separate storage for the salt or algorithm information.
You do need to salt because an unsalted hash is too easy to crack (using rainbow tables).
First, unsalted hashes result in more collisions. If two passwords used baseball as their password, cracking one is enough to crack both. If both are salted, so that one becomes baseball#sd7#$j and one is baseballL4&$h1, that doesn't work.
Second, a password like baseball or even *4kB$l!h_' is going to be easy to reverse using rainbow tables if it isn't salted. This is because it's easy to create a rainbow table covering all passwords up to a certain length. If properly salted, though, *4kB$l!h_' might be turned into *4kB$l!h_'H4Sj$8)#80-+2nm:W[oa}u#*4$lNamA{ or something else absurdly long. Generating a rainbow table for that is much, much harder.
With PHP, make your life easier and just use password_hash(). Whatever you do, do not roll your own security algorithms, especially with respect to password storage. You will get burned.
For lots more information, read Why are salted hashes more secure? You may also want to spend some time with OWASP's Password Storage Cheat Sheet and it's PHP Security Cheat Sheet.
it does help against 'rainbow tables', which are precompiled hashes for known passwords. when you salt the password, they are useless, because the hash will be different.
I would like to point out the real purpose of using salts. As explained in another answer, different salts lead to different hashes for identical passwords, but this is not the main purpose.
With using different salts for each password, you prevent building one single rainbow table to get all passwords at once.
As you wrote, the salt is not secret. To get a single password, an attacker could still build a rainbow table using this known salt. The problem is, that (s)he would have to build a second rainbow table for the second password, because it used a different salt. In other words, the first rainbow table cannot be reused to find other passwords.
Building a rainbow table to get only a single password doesn't make sense, it is easier to brute-force until you find a match, calculating the rest of the rainbow table is useless since you cannot reuse it. That's why we say, unique salts prevent rainbow table attacks, because brute-forcing is faster than working with rainbow tables.
Recently i was reading a book regarding a safe way to store a password in the database. The book started with MD5, SHA1, and CRYPT_BLOWFISH. From what i read i understand that the safer way to store passwords is by using CRYPT along with random salt per user(a value that the user inserts in while registrating, like username for example), without storing the salt in the database.
So, lets say that i generate a salt:
$salt = '$2y$11$';
$salt = $salt.md5($username);
As we know a MD5 hash is a 32 character long string. So 7+32 = 39 character string = SALT
Something like this: $2y$11$243dc6440dfd91e35a773035da362f4e
Then i generate the hash using crypt():
$hash = crypt($password,$salt);
The crypt hash always results in a 60 character string. The result is:
$2y$11$243dc6440dfd91e35a773uY4TBuP14hk.KZq4VvOWV8EhT03Vj8Tu
If a hacker gain access to the database, he/she will see the part $2y$11$ of the 60 character string above.
My question is: Is this info helpful for the hacker (knowing the hashing method and the cost)?
Should I store the hash omitting that part? 243dc6440dfd91e35a773uY4TBuP14hk.KZq4VvOWV8EhT03Vj8Tu
Will this make things worse for the hacker?
Other than these, are there any other suggestions regarding password security AFTER the hacker gains access to the database?
There is a tutorial i wrote about safely storing passwords, it explains why it is not necessary to hide the hash parameters.
If you hide this parameters you actually add a server side secret (an attacker has to guess the algorithm and the cost factor). There are much better ways to add such a secret though, have a look at the last part of the tutorial about encrypting the hash-value with a server side key.
A salt is used to defend against dictionary attacks and rainbow table attacks becasue the resulting hash is different due to the randomly generated salt which was added to the password.
The salt is saved with the hash so that the hash can be regenerated from the password+salt.
So because of this the salt needs to be saved and so what you have done is one possible way of doing this.
The reason this is not helpful to the hacker and won't make things easier is because the whole point of a hashing algorithm is it's resistance to being reversed. Dictionary attacks and rainbow tables work by using known hashes that have been derived from a "word" to a hash. With an added random number in front of the original "word" the hash is completely different and so to create a dictionary or rainbow table with all possible salt values (for a given length salt) would be a huge database and take way too much time for the hacker to crack or even bother attempting.
The system appears to be a 3 part system.
A Salt to prevent Rainbow Table Attacks.
The Salt itself is protected by using some pseudo random data.
The Base Salt and the pseudo random data is mixed and used as the Final Salt.
With the 3 parts above you have a system that is resistant to Rainbow
Table attacks (1).
The System is further resistant to Finding a Rainbow
Table for your Salt. (2).
So if your system is compromised, an
attacker would have to generate a Rainbow Table for each User
Account. This is essentially equivalent to cracking that/each users
password. (3).
Or so Would the theory go.
md5($password.md5($password))
is this good enough for password hashing? I am not asking for comparing this to something like bcrypt.
if it is not secure, tell me why.
The reason to use a different salt for each user's password is so that an attacker can't take a list of all the hashed passwords and see if any of them match the hash of something easy like "password" or "12345". If you were to use the password itself as salt, then an attacker could calculate md5("12345".md5("12345")) and see if it matched any entries.
As I understand it, there are four levels of hashing you can use on a password table:
None - store the password as plain text. If someone gets a copy of your database, they have access to all accounts. Plain text is bad, 'mkay?
Hash the password - store the hash of the password, and throw away the real password. If someone gets a copy of your database, they can't see any passwords, only hashes. However, if any users have used weak passwords, then their hashes will appear in rainbow tables. For example, if a user has the password "password", then an md5 hash stored in the database would be "5f4dcc3b5aa765d61d8327deb882cf99". If I look up that hash in a rainbow table like the one at gromweb.com, it spits out "password".
Use a salt value - choose a large random string like a GUID and store it in your configuration file. Append that string to every password before calculating a hash. Now the rainbow table is far less likely to work because it probably won't have an entry for "password59fJepLkm6Gu5dDV" or "picard59fJepLkm6Gu5dDV". Although precalculated rainbow tables are not as effective anymore, you can still be susceptible if the attacker knows your salt value. The attacker can calculate the hash of a weak password plus your salt and see if any user in your database uses that weak password. If you've got several thousand users, then each hash calculation lets the attacker make several thousand comparisons. How you actually use the salt may depend on the encryption algorithm you're using. For simplicity, just imagine it as appending the salt and the password together.
Use a distinct salt value - now you take something distinct like the user name, e-mail address, or even user id, and combine that with the password and the large random string from your configuration file before you calculate the hash. Now an attacker who knows your salt still has to recalculate the hash for every user to see if they have used a weak password like "password".
For more details, check out the Coding Horror post, "You're probably storing passwords incorrectly".
Although it seems quite enough to me, it will be in danger in case if someone precomputed a rainbow table based on the same algorithm (what is quite possible).
So, I'd rather use an email for the salt which seems pretty secure yet usable. Paranoids may add some constant site-wide salt.
People often makes too big deal out of password salt (in theory), while in their applications they allow simple passwords and transfer them in plain text over insecure HTTP in practice.
Every freakin' day I see questions regarding salt or hash.
And not a single one regarding password complexity. While
The only your concern should be password complexity.
Why? Let me show you.
extraordinary good salt + weak password = breakable in seconds
It is always assumed that salt is known to attacker. So, by using some dictionary of most used passwords and adding [whatever extra-random-super-long] salt to them, a weak password can be discovered in seconds. Same goes for brute-forcing short passwords.
just sensible salt + strong password = unbreakable
Quite unique salt makes precomputed tables useless and good password makes both dictionary and brute-force attacks good for nothing.
It doesn't do much against dictionary attacks, only twice as hard to compute a dictionary versus a single md5, and md5 is pretty cheap these days.
MD5 is not secure in itself because it is partially broken (collisions) and is too small of a digest anyway. If one doesn't want to use a proper password derivation function à la bcrypt, scrypt or PBKDF2 you should at least use SHA-256 for new designs (and have a plan to migrate to SHA-3 when it will be out, so be sure to store the scheme you used to hash the password with the result, so both scheme can coexist as you use the new hashing procedure when people change passwords).
If you intend to sell your program using MD5 in any capacity can be a show stopper for most government sales (e.g. in the US algorithms used must be FIPS 140-2 approved and many other countries got the same kind of requirements).
The reason why random password salt is recommended for hashing password, so that an attacker who knows the password hash can't compare it to rainbow table of pre-calculated hashed from dictionary.
If you're using password as salt, attacker can pre-calculate hashes of $word.md5($word) first from their dictionary
With your solution you pretty much defeats the purpose of using a salt against precomputed dictionary attacks.
With a precomputed dictionary, as the name implies, someone has already created a table of hashes (the computed md5 result) for particular words, ahead of time.
Consider this table hashtable (with imaginary hashes, just for illustration purposes)
word | hash
------------
foo | 54a64
bar | 3dhc5
baz | efef3
Testing these values against your table, could be as simple as:
SELECT h.word
FROM hashtable h, yourtable y
WHERE y.password = MD5( CONCAT( h.word, h.hash ) );
With a match, you'ld have the password.
However, if you did NOT hash the password, before concatenating it again with the password and hashing it once more, it would be more difficult to attack it with a pre-computed dictionary. Because then the password would be for instance md5( 'testtest' ) which makes the precomputed table worthless, if the precomputed table has only taken into account single instances of the word.
You can easily see that it gets even more difficult if you did not use the password as a salt, but used another random string as salt. And it gets even more difficult still, when you create unique salts for every passwords. Of course, if you create unique salts per password, you'd have to save the salt in a separate column along with the passwords in a database row.
So my advice would be:
md5( 'uniquesalt' . 'password' );
Or actually, don't use md5 at all, but use the far better sha1, sha256 (or higher) hashing algorithms.
I've been told that email is a bad salt, because it's not unique and connected to the user.
And if a user uses the same password on 2 sites, there will be equal hash.
So, what's wrong with it? what is attack scenario?
Suppose we have both hash and salt. So, other site has the same hash in their database.
How can we do any harm to this user on the other site? Can we at all?
I don't see any possibility, but I am not an expert in security, so, I'd like to hear from ones who are, with practical and concrete answers, of course.
I am not going to break anything. I am asking this question in the context of this one: is email or (registration timestamp) a good salt?
Certain and practical answers, please.
The point of a salt is not to be unknown, it is to prevent attackers from amortizing the cost of a brute force or dictionary attack across all users of a site (or even all users of many sites).
Thus, the problem of using a non-random salt like the email address is that it would show an attacker which users are using the same password on several sites, and which would therefore yield access to several accounts at once if cracked via brute force or dictionary attack. For the email address (and everything that is unique per user), this is a rather hypothetical problem since it assumes the attacker has the account data of several sites with considerable overlap in users.
Another problem with using the email address is that users will want to change it - which would be impossible if you use it as salt unless you store it in a separate salt column as well or require people to always change their password together with their email.
This is mostly a theoretical question. So, how does "cracking a hashed value" work? There are so called "rainbow tables", that are just list with common words and theire hash value. For salted hashes an attacker needs such tables also with salted hashes. So in theory with unique salts for every user an attacker needs one table for every salt (=> user). If you have a static salt, he "just" needs one table for your db. Its quite expensive to create such tables, so in most cases its not worth to create it just for a single page.
Conclusion: Its (of course) safer, to use unique salts for every user, but on a veeery high level. A static salts is usually "safe enough".
The first attack I can think of is:
a user has the same salt and password at two sites
both sites have a flaw to allow reading the salted passwords
one site makes reading a password or brute-force guessing a password easy
An attacker could quickly look at identical salted passwords on both sites and find users with identical passwords at both sites. Then read the password or guess the password on the weaker site, and use it on the more secure site.
Granted, different salts wouldn't make the problem significantly better because all million passwords can be tried eventually. But knowing which users have identical passwords would be much 'quieter' than just blindly trying all the users' passwords on the stronger site.
Think of the web sites you've programmed - I bet the most powerful users in these systems have very common usernames like admin, root, etc. As an attacker I can generate a precomputed hash list containing the most common usernames with the weakest and most common passwords - that is, if a web programmer is naive enough to salt their passwords with usernames, my job as an attacker has become much, much easier - the collisions are very predictable.
Using an email address as a salt is better, but the same principle applies. Assuming I've cracked one database that uses an email-based salt I'll have a much easier time cracking every other database that does the same - at least, for email/password combinations that exist across databases. (Given the amount of login reuse, that's a very likely). It's not as simple as with the username salts, but the collisions are out there, waiting to be discovered.
As a programmer what I really want is a password hash that won't collide - ever. A universally unique hash for each user that can't be found in any other database in the world. That's a tall order, but it's doable with a sufficiently long, randomly generated salt.
There's a herd immunity effect in play - using a bad salt makes it easier for attackers to attack similar systems after they've compromised your database. A strong salt will always protect your users and help other userbases from being compromised.
Can't really help you in terms of security, but if you look at vBulletin for example, each user gets their own generated salt, which they use the encrypt the password like this:
$password = md5(md5($clear_password) + $salt);
So the salt will be different for each user and any site where vBulletin is running (at least a pretty good chance that it will be different), so the stored password, in turn will be different for each site.
It's not what you were asking for, but something to meditate on :)
Assume the hacker has both password and salt, AND access to your hashing formula.
This will NOT prevent a dictionary attack, contrary to popular beleif. It will stop a simple dictionary attack, but iterating the dictionary with the salts per user account is perfectly possible.
See: Why do salts make dictionary attacks 'impossible'? for more related information.
This is why when you generate the hash of the password, instead of hashing once with salt, IE:
hashedPW = sha1(rawPassword + salt)
You would do:
hashedPW = sha1(rawPassword + salt)
for i = 0; i < 2000; i++){
hashedPW = sha1(hashedPW + salt)
}
The multi hash function should take a significant fraction of a second to calculate. This means when the hacker gains access to the database, the dictionary attack then becomes exponentially more time consuming only allowing him to crack a very small % of user accounts.
If the salt is already known, then you have bigger problems on your hands.
http://en.wikipedia.org/wiki/Rainbow_attack