PDA

View Full Version : Password Hashing - PHP


llbbl
03-23-2005, 10:08 AM
Both of these weaknesses in the hashing strategy can be overcome by making a small addition to our hashing algorithm. Before generating the hash we create a random string of characters of a predetermined length, and prepend this string to our plain text password. Provided the string (called a "salt") is of sufficient length - and of course sufficiently random - the resulting hash will almost certainly be different each time we execute the function. Of course we must also store the salt we've used in the database along with our hash but this is generally no more of an issue than extending the width of the field by a few characters.

When we validate a user's login credentials we follow the same process, only this time we use the salt from our database instead of generating a new random one. We add the user supplied password to it, run our hashing algorithm, then compare the result with the hash stored in that user's profile.


<?php

define('SALT_LENGTH', 9);

function generateHash($plainText, $salt = null)
{
if ($salt === null)
{
$salt = substr(md5(uniqid(rand(), true)), 0, SALT_LENGTH);
}
else
{
$salt = substr($salt, 0, SALT_LENGTH);
}

return $salt . sha1($salt . $plainText);
}

?>

Note: The function above is limited in that the maximum salt length is 32 characters. You may wish to write your own salt generator to overcome this limit and increase the entropy of the string.

Calling generateHash() with a single argument (the plain text password) will cause a random string to be generated and used for the salt. The resulting string consists of the salt followed by the SHA-1 hash - this is to be stored away in your database. When you're checking a user's login, the situation is slightly different in that you already know the salt you'd like to use. The string stored in your database can be passed to generateHash() as the second argument when generating the hash of a user-supplied password for comparison.

Using a salt overcomes the issue of multiple accounts with the same password revealing themselves with identical hashes in your database. Although two passwords may be the same the salts will almost certainly be different, so the hashes will look nothing alike.

Dictionary attacks with pre-generated lists of hashes will be useless for the same reason - the attacker will now have to recalculate their entire dictionary for every individual account they're attempting to crack.

http://phpsec.org/articles/2005/password-hashing.html

Good article.

llbbl
03-23-2005, 10:12 AM
Since sha-1 has been cracked I wonder if this hash algorithm actually provides any amount of increased security for passwords. Seems we should be using a different algorithm instead.

Keamos at gmail dot com
05-Mar-2005 03:19
Or, you could use cryptopp-php (a PHP version of crypto++), which you can get at http://bugs.tutorbuddy.com/versions.php/cryptopp-php

It supports (for hashing):

MD2
MD4
MD5
RIPEMD-128
RIPEMD-160
RIPEMD-256
RIPEMD-320
SHA1
SHA-256
SHA-384
SHA-512
Tiger
Whirlpool
(SHA256/384/512, Tiger and Whirlpool only on systems using word64)


I found this one. I think i would try this one as an interem solution.

k2
04-08-2005, 07:11 AM
i know this is kinda old .. but encrypting a password doesn't secure a database or system. implimenting a proper authentication system using ssl is the only way you can do it.

sending a plaintext password unencrypted to be checked against a hash does not make the db secure; the password is still sent as plaintext. using multiple hashes/keys to authenticate a user instead of storing a password in a cookie is a good start.

dang
04-08-2005, 09:13 AM
i would have to agree with k2 on that. The only reason to really encrypt passwords in a db is in case someone gets into your db.

If you dont use ssl when submitting passwords via the web, then they can just sniff.

k2
04-08-2005, 09:19 AM
well, if someone's in the db .. an encrypted password field is not going to stop them from browsing tables or deleting information (only permissions is).

even perms are only useful if you're in a multi-host environment were 1 hack won't be able to drop your db, or read it's contents.

llbbl
04-08-2005, 10:47 AM
It helps protect against type attacks called sql injection. There are other measures you should take in addition to using a secure hash to protect yourself.

http://www.spidynamics.com/papers/SQLInjectionWhitePaper.pdf

This is an example of where the attacker does not have the db password, but uses a specially formluated attack to get the results back from the db of the username / pass of the database. If the database password isn't protected by a secure hash then they will be able to obtain an account with root privlages and cause some serious damage.

So am important thing to remember here is that there is more than one way to perform an attack and just because you have a SSL encryption doesn't mean your system is totally secure. Sniffing the network for root passwords is ONE of the methods for gaining access.

llbbl
04-08-2005, 10:58 AM
Anyways there is a way to encrypt the username / password securely without SSL. You can use Javascript, since it it client side executed you can encrypt the information before it is .

Examples of MD5
http://perl-md5-login.sourceforge.net/
http://pajhome.org.uk/crypt/md5/

More secure implementation :) notice its based in netherlands due to export control laws on encryption programs.
http://home.zonnet.nl/MAvanEverdingen/Code/

Here is a fun demo of Pontifex algorithm from Cryptonomicon.
http://pfex.sourceforge.net/

k2
04-08-2005, 11:39 AM
that technique doesn't stop an sql injection. most beginners have a query in php or some other language which is formed with variables collected from user input; usually a form.

replacing ' with '' and blocking ; is how you stop an sql injection in that scenario. as you get into higher level dbs, processing variables before or after they're sent to a stored procedure is how you stop an injection attack.

llbbl
04-08-2005, 01:24 PM
i am agreeing with you. all i was saying that if you are not doing form validation to check for these values, and a person useses this method to get a dump of the User table or wherever else your db stores its accounts information than they could get a list of the usernames and passwords. if the passwords are in plain text or MD5 encoded than it is likely at this point that the attacker will have your passwords as well. you should setup restrictions by IP or ranges of IP on your db root account. ideally root would only be able to connect from localhost and you would have a remote account that is IP restricted and not able to change user account permissions.

llbbl
04-08-2005, 01:36 PM
normally MD5 can also be used to validate if information is true or not. For instance you might save the results of a form and generate the MD5 of it. Your form might have a preview function and if the user clicks it and then Post/Sumbit from the preview page you could check the original has against the new data to see if there is any differences.