Hi Anthony,
MD5 and SHA1 password hashes are considered weak. You are correct that
someone got a hold of your hashes they could use a dictionary of
common passwords to devise some of your user's passwords.
There are a few ways to deal with this. The simplest is to just force
users to create complicated passwords. Make them use passwords that
are at least 8 characters and contain at least one digit and one
non-alphanumeric character. This makes a dictionary attack much less
practical (but by no means impossible if you have a lot of resources).
The other way is to use a hashing algorithm with a larger bitwidth.
Another is to add a salt. Better still, use all of these techniques.
One pedantic note: MD5 and SHA1 are not encryption algorithms. They
are hashing algorithms. With encryption you take plaintext and convert
it to ciphertext and then you can do the reverse and get the plaintext
back. With hashing you take plaintext and convert it to a hash which
is just a random bit of data but of course given the same input you
always get the same output. But with a hash you cannot convert it back
to plaintext.
Personally I recommend that you do not invent your own hashing
algorithm. It only creates an opportunity to make a mistake that can
be exploited and it does not increase security anywhere near as much
as increasing the bitwidth. Just use a standard hashing method so that
passwords can be migrated, code is understood and can be ported, etc.
I would recommend using SSHA256 which is computed as follows:
1. Convert the plaintext password to UTF-8. In PHP you can use iconv for this.
2. Generate an 8 byte random salt. In PHP you can use mt_rand for this.
3. Generate the SHA256 hash of the UTF-8 plaintext password + salt. In
PHP 5 you can use hash_init('sha256'), then hash_update($utf8password)
followed by hash_update($salt) and hash_final to get the hash.
4. Concatenate the hash followed by the salt, convert the result to
Base64 and then prefix it with the "{SSHA256}" label to get a result
that looks like:
{SSHA256}1LzicRO5StQs9kSR4UvTZbgfyhiiknzwDUhKaAgXUEa1uyL/s1Pd/A==
Here's an example with real values and salt used so that you can check
your computations as you go:
Plaintext:
opensaysme
Salt in Hexadecimal:
B5 BB 22 FF B3 53 DD FC
SHA256 Hash of Plaintext and Salt in Hexadecimal:
D4 BC E2 71 13 B9 4A D4 2C F6 44 91 E1 4B D3 65
B8 1F CA 18 A2 92 7C F0 0D 48 4A 68 08 17 50 46
SSHA256 Text Representation (this is what you put in the DB):
{SSHA256}1LzicRO5StQs9kSR4UvTZbgfyhiiknzwDUhKaAgXUEa1uyL/s1Pd/A==
Note that even though I show the values in hex for the purpose of this
message, all of the computations are done using binary which means in
PHP you're going to need to write helper functions that use ord and
chr quite a bit.
This 256 salted password hash is standard and is understood by
software like LDAP servers. Combined with complex password
requirements, this would disappoint even a serious cracker.
If your system does not support sha256, do SSHA128 instead using the
sha128 algorithm (aka sha1) + salt. Otherwise it is computed in
exactly the same way but of course it will only be 128 bits instead of
256. But at least you'll have a salt which will greatly slow down a
dictionary attack.
Mike
And even more excellent advice -- my notes on this are overflowing.
Cheers,
tedd
--
-------
http://sperling.com http://ancientstones.com http://earthstones.com
_______________________________________________
New York PHP Users Group Community Talk Mailing List
http://lists.nyphp.org/mailman/listinfo/talk
http://www.nyphp.org/Show-Participation