Main
Latest
- Opposites
- Cape Town - Here we come!
- Microsoft DNS Server
- RFC 3339 Timezones in Joomla! 1.5
- TinyLink, Ajaxified!
- Tinylink API: Consumer PHP Shell Script
- Teh First Law of Pwnage
- Lithium, Batteries & Recycling
- Muti.co.za & Censoring
- Milkshakes
Archives
- June 2004
- July 2004
- August 2004
- September 2004
- October 2004
- November 2004
- December 2004
- January 2005
- February 2005
- March 2005
- April 2005
- May 2005
- June 2005
- July 2005
- August 2005
- September 2005
- October 2005
- November 2005
- December 2005
- January 2006
- February 2006
- March 2006
- April 2006
- May 2006
- June 2006
- July 2006
- August 2006
- September 2006
- November 2006
- December 2006
- January 2007
- February 2007
- March 2007
- April 2007
- May 2007
- June 2007
- July 2007
- August 2007
- September 2007
- October 2007
- November 2007
- December 2007
- January 2008
- February 2008
- March 2008
- April 2008
- May 2008
- June 2008
- July 2008
- August 2008
- September 2008
- October 2008
- November 2008
- December 2008
- January 2009
MD5 and SHA-1 Password Hashing in PHP / MySQL
It is pretty standard at the moment for PHP-based CMSes to use MD5 hashing for user login passwords that are stored in a database. This means that even if somebody gets read-only access to the database, they still can't log into the site. (The point behind hashing is that it's one-way only - hashes should not be able to be decrypted.) The reason for MD5's popularity is partially because PHP just makes it so easy. However, I only discovered today that it's just as easy to do SHA-1, which seems to be generally considered as substantially stronger. Take a look at the PHP sha1 function documentation.
I just wrote this little shell script to generate SHA-1 hashes on the go (it's just copied from another script I wrote earlier for generating MD5 hashes):
#!/usr/bin/php
<?php
if (count($_SERVER['argv']) < 2) {
echo "Error: At least enter something to hash, noob!\n";
exit(1);
}
foreach ($_SERVER['argv'] as $i => $text) {
if ($i) {
echo "$text\t" . sha1($text) . "\n";
}
}
If you would like to learn more about MD5 and its problems, check out MD5 Vulnerabilities on the Wikipedia.
So, are there any reasons not to migrate? Time to change the user/login management classes and change the CHAR(32) database field to a CHAR(40), because the "normalised" strings the sha1 PHP function returns by default are 40 characters in length instead of the usual 32 for MD5 hashes.
Migration of existing databases will be a big problem though, as you can't (or shouldn't be able to) decrypt the existing passwords for re-hashing. You could probably hash the MD5 hashes with SHA-1 (thereby double-hashing) though if you really like, or try your luck with large MD5 rainbow tables. Maybe you get lucky and all your users are noobs with < 8 character passwords (just kidding). Please note that SHA-1 (such as any other hashing function) is also still vulnerable to rainbow tables.
One last point I wanted to address, although this is somewhat off-topic. Why do people use VARCHAR field types in MySQL databases for storing hashes if they will always be the same length? Isn't it more efficient to just use CHAR? I believe the latter is more efficient in cases like this - please see the comments on the page The CHAR and VARCHAR Types for more information.
Update: Peter Rotich pointed out to me that a simple strategy would be to allow both MD5 and SHA-1 hashes in the database. A user's MD5 hash is kept and as soon as he logs in using the correct password matching up with the MD5 hash, the password is hashed again using SHA-1, stored and the MD5 hash is deleted out of the database. Next time the user logs on, their password is checked against the SHA-1 hash. Smart one, Peter, thanks!
Copyright © 2004-2009 Charl van Niekerk. All articles are released under the Creative Commons Attribution 2.5 South Africa licence, unless where otherwise stated.


4 Comments
Comment by
Tom-Eric on Tuesday, October 30, 2007 8:29:00 AM
Judging by this sentence:
The CHAR and VARCHAR types are similar, but differ in the way they are stored and retrieved. As of MySQL 5.0.3, they also differ in maximum length and in whether trailing spaces are retained.
I think the answer to your question is, most people aren't used to it making a difference.
Comment by
Charl van Niekerk on Tuesday, October 30, 2007 8:53:00 PM
For me it's simply logical to use CHAR because the nature of VARCHAR is the variable ("VAR") part. But yeah, I think most people don't think that far.
Comment by
Tom-Eric on Wednesday, October 31, 2007 8:04:00 AM
Well I know I used to think this far in the past, but it didn't make a difference back then, because MySQL still treated the CHAR field type the same as the VARCHAR field type.
I also doubt it makes a notable difference in speed or storage, but I'm not sure.
Comment by
Charl van Niekerk on Wednesday, October 31, 2007 12:10:00 PM
Yeah let's face it, with today's storage and processing facilities, nobody is going to bother unless the respective table(s) are gigabytes in size.
Post a Comment