Before I knew better, I implemented a login system with md5 as the hashing algorithm. Now that I do know better, I'd like to move to using PHPass. My problem is that the system is already in production and asking all users to change their passwords would be the mother of all headaches.
I've come up with a simple enough solution, but given my previous mistake I'd like to make sure I'm not making an equally grievous mistake due to ignorance.
My solution is as follows:
Change
md5($_POST['pass'])
- check md5 hashed password against database value
To
md5($_POST['pass'])
- pass md5 hashed password to
$hasher->HashPassword()
- use
$hasher->CheckPassword()
to check the re-hashed password against value from DB
Just for clarity, I'm only re开发者_Go百科-hashing the md5 version because that's what I already have in the DB. It's not intended as an added security measure (although if it is, that's great!).
MD5() problem is WAY exaggerated on this enthusiast programmers community site. Nothing actually bad in this hashing algorithm, especially in comparison with other parts of usual newbie application. Using phpass techniques on a usual PHP site is like using a safe lock on a paper door of a straw hut.
Most important thing in keeping passwords safe against virtual possibility of being stolen and used against the same user on other sites (oh, my!) is password strength and salt. Not hashing algorithm itself. No hashing technique would protect silly pass like "1234" or "joe".
So,md5 + strong password + average salt
is better thanusual password + phpass
There is not a ingle reason to phpass existing md5 hash
A sensible migration algorithm is- check this user record for the new hashing flag.
- if it's set -
- go for phpass auth
- if not:
- md5($_POST['pass'])
- check md5 hashed password against database value
- if correct:
- phpass($_POST['pass'])
- save result in the database
- set new hashing flag for this record
- done
The problem you're talking about isn't really specific to PHPass, but hashing passwords in general. It's basically just double-hashing. This topic has been talked about already in another question: Is "double hashing" a password less secure than just hashing it once?
If you have a look there, you can see that there is still debate over whether double hashing is worse, since it reduces the range of characters passed into the second (or subsequent) hashing function. However, it slows down the hashing process, combating brute force attacks, but only doing it twice won't act as much of a speed bump.
If you didn't want to have to deal with the double hashing, what you could try doing was adding a flag field to your users
database table, and set that to true
for all new users who join after you setup the new PHPass form of hashing. Then, when a user log in, if they don't have the flag field set, use the old hashing system, or the modified version you have detailed in your question. If they do have the flag field, you can use whatever new hashing process you have set up.
Update: Actually, building on that, what you could try is having that flag setup, and once they go to log in under the old system, if it is a match, then you'll still have their unhashed password in your $_POST
data, so you can then run that through your new hashing setup, save the new hash, then set the flag to true
, since they've been upgraded to the new hashing method. From then on, they'll be using the new hashing method.
You're getting some pretty dubious advice here, so you might want to ask on IT Security. Contrary to what some folks have said, the password hashing algorithm does matter; you want to use salting and a slow hash such as bcrypt, scrypt, or PBKDF2. See: Which password hashing method should I use?, Do any security experts recommend bcrypt for password storage?, How to securely hash passwords?, Most secure password hash algorithm(s)?. PHPass is a good library.
To migrate your users over to PHPass, you'll want to have two password hash databases: the old one (with MD5 hashes), and the new one (with PHPass hashes). Initially, the new one will be empty. When a user logs in, check whether you have an entry for them in your old password hash database (with MD5 hashes), and if you don't find an entry there, look in the new password hash database (with PHPass hashes). If you find an entry in the old database, you'll want to use MD5 to hash and check their password. If it is correct, you'll want to hash their cleartext password using PHPass, insert it into the new password hash database, and remove them from the old password hash database. If you don't find an entry in the old database, you can check for an entry in the new database and check the validity of their password with PHPass. Basically, you gradually migrate each user over from old-style to new-style hash when they next log in. Does this make sense?
My method makes sure that the password is at least 8 characters long and contains non-random garbage characters ("garbage" meaning possibly unprintable/null characters):
function pass_hash ($password) {
# take first 8 characters of the raw md5 hash
$hashslice = substr(md5($password, true), 0, 8);
# add it to the password and hash again
return md5($password . $hashslice);
}
If you don't like md5
, just use sha1
, the principle is the same.
精彩评论