GirlProgrammer
GirlProgrammer

Reputation: 201

Going from unsalted to salted MD5 passwords

I have a LAMP (PHP) website which is becoming popular.

I played it safe by storing the user passwords as md5 hashes.

But I now see that's not secure; I should have salted the md5 hash - because it's currently possible to decode unsalted md5 hashes using rainbow tables.

What can I do?

I don't want to make everyone type a new password.

Upvotes: 20

Views: 9542

Answers (12)

user1114
user1114

Reputation: 1169

If you're moving away from MD5, you should go skip simply salting and go to an even better technique called stretching. In particular you should use bcrypt (implemented as PHPASS with php).

Here is a great link on why bcrypt: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html

And here is a short How To: 1. Download the phpass package: http://www.openwall.com/phpass/ 2. Look at test.php for examples like the one below:

require 'PasswordHash.php';
$t_hasher = new PasswordHash(8, FALSE);
$correct = 'plaintextpassword';
$hash = $t_hasher->HashPassword($correct);
$check = $t_hasher->CheckPassword($correct, $hash);

If $check===true (which is the case above) then the password is correct. If your password is 'hello', you would hash it using HashPassword, put the hash in a database, and when a user logs in, call CheckPassword(userenteredpassword,hashInDb) to see if the password is correct

Upvotes: 0

OIS
OIS

Reputation: 10033

Salt the original hash as mentioned by others. Just a few pointers here:

  • Salts are better the longer they are. Also if they contain more then just [a-z0-9] but length is better first of all.
  • If someone already has a copy of your DB and you rehash the same passwords with salt, the rehash the old hash with salt will not work. Instead you really should force users to make a new password.
  • You should match new passwords (and passwords to be salted) up against various lists of the most commonly used passwords. These are used in "brute force" attacks. Prompt/force the user to change the password.

Upvotes: 0

knittl
knittl

Reputation: 265211

sadly, your only way is to tell your users to renew their passwords.

you could also generate random passwords, but that is the same hassle.

edit

you could just double encode your stored passwords. so your new salted hashing algorithm would be:

md5(md5($new_password).$salt).':'.$salt

to update your old passwords use

md5($old_password.$salt).':'.$salt

to check if a provided password is correct simply use

list($stored_password, $salt) = explode(':', $salted_password);
if(md5(md5($provided_password).$salt) == $stored_password) {
  // you are now logged in
}

Upvotes: -1

Ryan McCue
Ryan McCue

Reputation: 1658

A great way to update the passwords while also making them more secure is to change to using a salted SHA1 for passwords. A SHA1 is harder to create a collision against, and it also has a different string length to MD5. A MD5 is 32 characters long, while a SHA1 is 40 characters long.

To convert these in PHP, you first check the string length of the stored password. If it is 32 characters long, check the password using your old method and afterwards, write a new one using SHA1 to the database.

If I remember correctly, this is precisely how WordPress handled this issue.

Upvotes: 1

Martijn
Martijn

Reputation: 5653

Two options here

  • Decode the passwords yourself, and re-encode them with a salt (I recommend something a little more fancy than MD5). You should inform the users that you're viewing their passwords unencrypted. It'll probably take a lot of time as well.
  • Make them retype their passwords, and store those salted and encrypted.

As far as I can see, there is no other way of recovering the passwords.

EDIT: Although MD5 is a hash and should not be decodable, it can be broken using rainbow tables: with probability almost one, you can find a unique (here's the probability) string of at most, say, 20 characters with a given hash, especially if your character set is limited, say, to alphanumeric. Strictly speaking, this is not decoding. For all practical purposes, it is. Extra note: producing the rainbow tables, and looking up 1000 password is still going to take a lot of time.

Upvotes: 0

Sam Becker
Sam Becker

Reputation: 19636

The answer is simple, make sure the keep a record or some sort of flag of which users have passwords on the new system of hashing, when they next login, authenticate them, calculate the new hash, flip the flag.

Now whenever someone logs in and the flag is set, authenticate them with the new hash.

Upvotes: 6

Jon Seigel
Jon Seigel

Reputation: 12401

You can migrate the passwords by adding a column in your tables to store the new format.

When a user logs in successfully, if the new column is empty, put the stronger password in there and empty out the original column. If the new column has an entry, compare the input to the value in there.

Upvotes: 0

Gumbo
Gumbo

Reputation: 655239

You can still use a salt. Just calculate another hash from the current hash together with a salt:

$newHash = md5($salt.$oldHash);

For new passwords you then need to use:

$hash = md5($salt.md5($password));

Upvotes: 4

Bombe
Bombe

Reputation: 83852

Dynamically re-encrypt the passwords when the users log in the next time, i.e. first check whether it’s correct, afterwards encrypt it with a salt and store it again.

Upvotes: 0

Jeremy Bourque
Jeremy Bourque

Reputation: 3543

You can salt them on the fly. Add a piece of code so that, when someone logs in, it does the normal process (computes the MD5 sum of the password and checks it against the stored hash) and if that succeeds, recompute a salted version of the hash from the clear-text password they entered, and store it in the password file.

The only wrinkle is that you'll need to add an indicator for whether each MD5 is salted or not, since you'll have a mix of both for a while. Or, for a minor loss of security, you can check each password salted and unsalted and if either one hits, accept the login. Of course, if you detect that it was unsalted, then you upgrade at that point.

Upvotes: 9

Dominic Rodger
Dominic Rodger

Reputation: 99751

Why not add a new column new_pwd to your user table, which stores the result of md5($originallyHashOfPwd . $salt). You can then precompute new_pwd and once that's done adjust your login checking to compare the result of md5(md5($entered_pwd) . $salt) to what's in new_pwd. Once you're done switching your login checking, delete the old column.

That should stop rainbow-table style attacks.

Upvotes: 5

Heiko Hatzfeld
Heiko Hatzfeld

Reputation: 3197

You can do a "2 step hashing" instead of creating a hash in a single step.

You could append each password hash to the username, and then hash it again. This will create an undecryptable hash thats salted with unique informations.

The usual process of salting is

salt+PWD -> hash

You could do something like: PWD -> Hash -> UserID+Hash -> Hash

(Note the UserID was only picked so a unique salt for each double hash exists... Feel free to make your salt more complex)

Upvotes: 21

Related Questions