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.
I've been reading a bunch of stuff about security and I'm just now starting to try and play around with the code. I want to use MD5 encryption with a salt. I ran across this nifty PHP script with random salt:
substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',5)),0,10);
It randomly generates some characters as salt, but then I was thinking: How would I go about checking logins? Do I remove the salt, or should I store it in the database?
You shouldn't be using MD5 for password hashing. See How can I store my users' passwords safely?
To answer your original question, the salt is stored alongside the HASHED password in the database. The salt is not meant to be secret if the hashed password is discovered. Its purpose is to prevent attackers from using rainbow tables.
Store it in database. Otherwise you can't compare password provided by user with hashed one.
Some even regenerate hash (with new salt) upon each successful login of given user, although commenters below argue this is not the best idea (see comments)
Okay, so salts are used for both one-way hashes and encryption. They make it harder to reverse the encryption or the hash. I think it's easier to draw the point out with hashes, so I'll write from that point of view, but the principles apply to encryption in general.
Imagine that you're saving passwords. One of your users chooses the word "kiwi" as a password. Because storing passwords in plain-text is stupid, you don't want to do that. You want to hash the password.
But, those pesky hackers out there have compiled huge databases of hash look-up tables. (Check this one out!)
So, how do we foil the hackers? By salting the user's input! The salt is a random string (or set of bits, properly) that is cryptographically combined with the user's input to produce a more secure hash.
For example, if the string to be hashed is still "kiwi" and our salt is "5m3d", a simple salt mechanism might concatenate the two into: "kiwi5m3d". The hackers probably have "kiwi" in their database, but probably don't have "kiwi5m3d". A good salting system will probably perform a much more complicated function than this.
So now the hackers need a new look-up database for each possible salt. Using a random salt means that the hacker will have to do a full-on brute force attack, rather than recycling previous computations or using someone else's look-up table.
You could choose a different salt for everything, or the same salt for all the things on your site. A different salt of each entity necessitates a new brute force attack for each entity, but it can make implementation more difficult because each salt must be saved, rather than having one global salt (which, for data which is already somewhat random, e.g. passwords, should be sufficient).
In the case of encryption, look-up tables are still a possibility, but the data to be encrypted is generally varied enough that they're not feasible. So it becomes a game of playing "guess the password". It's easy to guess "kiwi" and hard to guess "kiwi5m3d".
You will have to save the salt somewhere, because it's the only way to "know" what's been hashed or encrypted. In the case of a hashed, you compare the user's original hash against the salted hash of their input. In the case of encryption, you need the salt to decrypt the data.
Where do you go from here?
First, don't use MD5. I gave you a link to an MD5 look-up database above. The function's increasingly considered to be weak. The sha class of algorithms is a better choice.
Second, make sure you choose a good salt. Longer and randomer is better. Computers are kind of bad at generating random data. This site could be one good choice and has a pretty good break-down of how it generates its random numbers.
Third, consider salt algorithms. Simple concatenation should work, but maybe HMAC (something I don't know much about) would be better.
You would have to store it in the database, otherwise you would not have anything to compare it to. The thing to remember with using a salt, is that the complexity can vary and without knowing what the salt is, the likelihood of it being brute forced hack is dramtically decreased.
Example:
$password = "banana";
$salt = "a12dsfg33B1cD2eF3G"; # Can be any assortment of characters
$password = md5($salt.$password);
Then you would just attach the same salt (would have to match to work) and pass the same function to your login script that combines the salt and the supplied password. You would then check that to the value in your database to authenticate the user.
Do not invent your own password-hashing scheme, however nifty it may look. Having a secure system is hard because you cannot really test for security. What you need is the following:
For each password instance, a random salt of sufficient length is created.
The random salt is stored along the hashed value; you will need it to verify the password afterward.
The password hashing process must be (configurably) slow, with many (many) nested invocation of whatever hash function is internally used.
Preferably, the internal hash function should use operations which are efficient on a PC but slow on a parallel architecture (a GPU).
Such a thing exists, it is called bcrypt and you can get it in PHP with the portable PHP password hashing framework.
I'm reading so much conflicting advice as to how to store passwords securely. All I know for sure is not to use MD5! I've seen people advocate using PHP's bcrypt function, which seems like it'd hog the server's processor. I've seen advocates for salts, and advocates for not using salts.
It's all just so unclear. Is there real and credible advice as to how to store passwords securely?
Edit: After a fair amount of research, I found an article from ;login: that deals with the topic in quite some depth: http://www.usenix.org/publications/login/2004-06/pdfs/alexander.pdf
Well, there is several parts to this.
You need to try to make it difficult to get to your db and passwords in the first place, keep them secure. This includes not making your passwords cleartext and not using a symmetric encryption algorithm.
You need to use a salt. Doing this prevents people from using a precomputed lookup table (i.e. rainbow table) or something like http://md5.rednoize.com/. Pick some data for your salt that is both unique and unpredictable. I usually use a random 32 bit value, but I wouldn't go much less.
Some algorithms are stronger than others. This is defined in a couple ways
How fast it can be computed. Longer is better. The faster the attacker can calculate hashes, the better the odds are for a bruteforce attack.
If the algorithm has no known weakness which reduce the search space. For example, the number of bits in an md5 hash is misleading because there are known attacks that reduce the actual search space
As of today I think SHA1 or SHA2 with a salt is reasonably secure for the near future. There is a utility called bcrypt which uses an asymmetric variant of blowfish and has the concepts of salt and computational expense built-in, it might be worth checking out.
Edit: I wanted to clarify what a salt is, as there is a lot of misconception about it on SO and online.
What a Salt is not
A secret, pre-agreed upon string that you hash with the password. This is a secret key, not a salt.
What a Salt is
You include the salt (unique and unpredictable per hash) along with your password when hashing, but you also include a unencrypted copy of it outside of your hash, so that when verifying the hash later you are able to include the same salt when given a test password before hashing it so you can properly compare the hash.
The point of bycrpt is to hog the processor! (Relatively speaking.) It is for this reason that it is "better" for password hashing than SHA1/2. (This "better" assumes that the password hashes are already in the hands of the attacker or otherwise exposed; while it would nice if it were not the case, even big corporations have had security compromises.)
This requirement was explicitly considered for bcrypt -- if you can only process 1k hashes a second (still, that's a good bit of log-in attempts), how long will that take an attacker to brute-force? A good bit longer than if they could process 10 million hashes a second! The target attack space of a brute-force that is only of the allowed password input, which is often much smaller -- esp. in practice with "simple passwords" -- than the space of the hash!
And a salt is very much required to avoid rainbow tables which trade time for space :) A rainbow table would effectively need to be created for each unique salt value. (Thus, the more unique salt values, the more space is required and with enough values this becomes impractical for an attacker.)
Happy coding.
First of all you need to use a good hash function, I suggest SHA-256. You can create a SHA-256 hash like this:
$hash = hash('sha256', $password);
In addition you could also use salting like this:
$salt = 'salt here';
$hash = hash('sha256', $salt . $password);
Moreover, you can use HMACs, like this:
$secret = 'your secret';
$hmac = hash_hmac('sha256', $password, $secret);
The best way to create solid hashes is through salting and iteration.
You should loop the above functions until hashing takes 200ms.
You could also go ahead and use encryption, but that would be a bit overkill for most situations.
This is similar to this question: Methods for storing login information in database
Credible advice: Never store your passwords in clear text!
Beyond that you have some choices to make. As I mentioned in the response to the linked question, there are two camps: let some else store your authentication data or do it your self. If you decide to do it your self, then you need to come up with a hashing routine. This should probably include a salting your passwords.
You can use sha256. A good thing to do is to add extra information to the password such as username, userid, or some other data to it. This way, if someone hack your database, it will be impossible to use an existant hash database to find the password. They will have to crack the password starting from zero.
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.