can someone help me. I've been reading about salting a password to make my passwords more secure. The format I was going with is salt:password_hashed, so my code is md5($salt.":".$password_hashed). $password_hashed is a simple m5d string of the original password, and the hash is taken from mktime().
I don't understand how the salt works, do i need to save this in the database as well? If the salt is ever changing, how does this work?
If a user registered with the password 'password' and the time they registered was 1234567890 (as a unix timestamp). The password generate would be md5(mktime().":".$_POST['password']) or something lik that. But if a user trys to then login with 'password' the newly created salt would be different?
You have to store the salt too, you could for example just store the registrationdate and use that in your salt.
Your salt can be user's e-mail or username.
I recommend this approach:
hash_hmac('sha256', $password, $salt);
Salts defend against rainbow tables. The salt is generated when the password is saved, so when the user is created and whenever the password is changed. You can store the salt as a separate field in your database but you can also just concatenate the salt with the encrypted password, and storing both in one field. Because salts are usually of a fixed length, it's easy to separate the two later to verify a password for login.
It is worth noting that md5 "considered cryptographically broken and unsuitable for further use" according to US-CERT. You should use sha-256 instead.
I've been reading about salting a password to make my passwords more secure.
That's quite nonsense. No salt can make your password more secure.
do i need to save this in the database as well?
yes
If the salt is ever changing, how does this work?
It doesn't work.
if a user tries to then login with 'password' the newly created salt would be different?
How do you think? Can't you compare mktime() result with '1234567890' yourself (and resulting hashes as well)?
Related
I want to update my password setup that is currently using just MD5.
Now what I would like to do is use something stronger (maybe sha256) with unique salt per user.
The question is about the salt storage.
Do I go with storing the salt in its own column in the database?
Then hash salt + password and when it comes to login, call the salt and password from the database, to make one.
Or do I go the way of making a salt, by using the username, email and timestamp which would also give me a unique salt per user?
I am wondering, if someone got a hold of the database with salt as a column, they would know the salt for each user, then they could crack the password.
The salt is not a secret, it can be stored plaintext together with the hash. It is not even necessary to have a second field in the database. If you look at PHP's crypt() function, you can see, that the salt will be included in the hash value itself.
It's the job of the salt, to make already existing rainbowtables useless, because a rainbowtable has to be built for one specific salt. Using a different salt for every hash will prevent rainbowtable attacks, because you would have to create a rainbowtable for each hash. That's why it is not necessary to keep the salt secret.
I would recommend, that if you want to improve your password hash system anyway, you do it right, with a hash function that is slow. The article password hashes with bcrypt explains the important points of generating a hash for passwords.
Generate a salt per password, not per user.
Use a random (unique) salt, not one derrived from other parameters.
Use a slow hash function.
Last but not least, don't be afraid of doing it correctly, the code of your application can be as easy as your current implementation with MD5.
Forget MD5 or SHA. Use Bcrypt. (Blow Fish Crypt) Comes native with PHP 5.3 and above. (crypt method 2a) it is more secure and processes slower.
When using Bcrypt the salt is stored together with the hash in the same feild . There is no reason for a seperate one.
http://php.net/manual/en/function.crypt.php
Just reading on another post and someone says the salt is not a secret and can be stored a database column. So that answers my question
I'm starting to create a user system for my website, and what I want to do is to have the passwords encrypted, rather than plaintext. I'm using PHP/MySQL, so I figured crypt() is a good place to start. However, I'm brand new to cryptography like this, and I'm having trouble understanding exactly how it works. Does anybody know how to implement, at the simplest level, a way for passwords to be stored as an encrypted string, but always be able to be decrypted, without a security issue?
Passwords should be hashed, not encrypted. That is, you should not be able to decrpyt the password. Instead, you should compare hashes.
User sets password $password = 'hX4)1z'
You get hash of password and store to DB:
#
$pw = hash_hmac('sha512', 'salt' . $password, $_SERVER['site_key']);
mysql_query('INSERT INTO passwords (pw) VALUES ('$pw');
Customer comes back later. They put in their password, and you compare it:
#
mysql_query('SELECT pw FROM passwords WHERE user_id = ?');
//$pw = fetch
if ($pw == hash_hmac('sha512', 'salt' . $_REQUEST['password'], $_SERVER['site_key']) {
echo "Logged in";
}
PHP has some built-in has functions, such as md5(). When I was learning I found IBM's primer very useful - I'd highly recommend looking at that.
As an aside, I would advise against being able to decrypt a password. The only person who should know their password is a user! This is why we store hashed versions of passwords which we can check against, rather than storing encrypted passwords which can be decrypted..
I notice people make huge deals about storing passwords.
Agreed you shouldn't store passwords as plain texts, but if you store the one way hash and get rid of the password, hackers can still using algorithms to hack a hash hashing strings and comparing.
Also, if you encrypt with an algorithm that you can decrypt later, that can also be hacked by figuring out the algorithm of the encryption.
I think as long as no one can see the users' passwords outright and you simply make it difficult for hackers you're good, but people say you shouldn't encrypt because it can be decrypted but that's not fair because anything can be hacked.
Use md5 instead
http://php.net/manual/en/function.md5.php
http://en.wikipedia.org/wiki/Md5
You can use md5 or better hashing technique like sha1
See password hashing http://phpsec.org/articles/2005/password-hashing.html for more details.
I suggest using SHA2 with a salt to store your password.
To create a SHA2 hash, use this:
$hash = hash("sha512", $password.$salt);
A salt contains some extra characters to add to your password before hasing to prevent rainbow tables (databases of passwords and it's hashes). You can create one using a unique user info (like a user_id) or just create a random one and store it somewhere. Just make sure the salt is long enough.
Don't make use of MD5 anymore; it's old. See http://en.wikipedia.org/wiki/MD5#Collision_vulnerabilities for more info.
EDIT: These are one-way hashing algoritms. You can and should not be able to decrypt a password. If you can, then there is no point in using a hash to store passwords.
No, there is always going to be a security issue with regards to where you store the encryption password. This is why websites never store the hash of the password and not the password itself. When someone registers at your website and they enter the password, you store the hash (MD5 or SHA1 or whatever, as mentioned above) of the password. When they log in later you again hash the password they entered (by the same method used when storing it) and compare. If the hashes are the same then the passwords are the same (with a very high probability!) Any website that lets you recover your password is an insecure website.
I'm using salt to encrypt my users' passwords.
I'm using PHP, and here's a quick sample of what happens during a users registers.
Here it is:
PHP code:
// Gives me my random key. My salt generator.
$salt = uniqid(mt_rand());
// My password via what users inputs.
$userpwd;
// Then the encryption. I use a HMAC hash.
$encrypted = hmac_hash("sha256", $userpwd, $salt);
?>
Now that all works for me in my script. But my question is, how do I authenticate a user logging in? The new encrypted password is random, so I can't compare the password from the login form to the saved encrypted password in the database.
I've searched and can't find a solution. Maybe I haven't searched hard enough, but is there a way to decrypt the password? What can I do to authenticate the user with my script?
You need to generate a unique salt for each user's password, and then store the value of the salt somewhere you can retrieve it. For example, by saving the salt to a user table along with the username and hashed password. That way you can extract the known salt and run it through your function when you go to authenticate a user.
Here is an article that contains more information: Storing Passwords - done right!
And for more information about salts: salt-generation-and-open-source-software
You hash the user's inputted password the same way, then compare if the hash is the same as the one you stored.
if (hmac_hash("sha256", $_POST['password'], $saltFromDatabase) === $hashFromDatabase)
$login = true;
You also have to store the salt since it's different for each user. I would also recommend using a second salt that is constant across the application (stored on a hard config file, so that even if the database is compromised, the passwords are still safe).
Note: Hashing is not the same as encryption; It is an irreversible process.
You encrypt the password used to log in and compare it with the encrypted password in your database. :)
You compute the hash of the password user has entered, just as you do when registering them. Note that the code is semi-pseudo code, you need to adapt it to your libraries or functions.
$res = db('SELECT etc FROM users WHERE user=? AND pass=?',
$_POST['user'], hmac_hash("sha256", $_POST['pass'], $salt));
if(numRows($res) > 0) {
// continue with authentication
}
If the salt is stored in the db, then you have to either fetch it first, or do the comparison in the db.
You don't decrypt what you've stored. You hash the entered password and compare it with what was stored at registration. This is because if two hashes match then (to all intents and purposes) you can be confident that the source data matches.
Your salt needs to be constant, and not random. That way when you are checking the password against the hash, all you have to do is hash the input with the salt again, and the resulting hash should be the same as what came out before.
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.
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)
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.
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.
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.
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));
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.
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.
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.
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.
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.
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
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
}
I am connecting to a MySQL database with PHP and the CodeIgniter Framework. I want to store my passwords encrypted in the database and would like to know the best way to do this.
From a high level overview - don't encrypt, hash. And if you can, use BCrypt. Here's a long article explaining why BCrypt and why hashing.
Encrypting the passwords is a bad idea. If somebody gets your database, they're probably going to get the key you used to encrypt the passwords as well.
The real solution is to hash, salt, and then store the passwords. Jeff Atwood has an awesome post on this:
http://www.codinghorror.com/blog/archives/000953.html
And here is one discussing "rainbow tables," massive tables of words with their MD5 sums:
http://www.codinghorror.com/blog/archives/000949.html
The best way, in that it is both easy and secure, is to use phpass. If your PHP installation does Blowfish, it uses bcrypt; if it doesn't, it uses multiple passes of md5. Either way, it's more secure than straight md5 or sha1.
$hasher = new PasswordHash(8, false);
// Before storing a password
$hash = $hasher->HashPassword($password);
// To check a password against a hash
if ($hasher->CheckPassword($password, $hash))
// $password and $hash match
I always md5sum passwords before I put them into the database, and then also md5sum password login attempts to check them against the db. Just for safety, I do a select query using a where clause with userID (username) AND md5summed password so that I don't get any rows back at all unless both match.
Also, mysql interanlly uses md5summing on it's passwords if you need a level of trust in this method of password obfuscation.
Use a hashing function; MD5 will do fine. Don't store the password, store the hash. Then, to log users in, hash the password they entered and compare it to the hash in the database; if the hashes match, they're legit.
Also, add a salt to the password before you hash it. This can be easy as just appending a string to the password, like your domain name or some other data that's unique to your app. This prevents hackers from using rainbow tables against your hashes.
Never store passwords. Use a one way hash and store that.
hmm, I hash, more than once based on whatever math springs to mind at the time of writing the storing and validation of passwords
From here on I'll probably go with OpenID as much as possible wherever I have an actual choice tho, so i don't have to do any password storage at all. That way I can leave passwords up to the experts, and the users already trusted party.
I agree with hashing and salting. I disagree with picking a site-wide hash. Use a different salt for each user to prevent dictionary attacks against all your passwords at once.