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
Related
I'm working on a site which is (try to be) super secure. I read a lot about password hashing and using salts, but not everything is clear to me. I would like to use sha-256 hash algorithm with salt. I know about salts that all of them should be unique per-user per-password.
I'm wondering what if I use the password as salt too? Hash the password with sha256 and then hash it with an other algorithm and use it as salt. In this way I don't have to store the salt in the database. Is this possible? or should I generate a random string?
No, that is still a one-way algorithm.
If another user uses the same password the hash value will be the same as the hash of the pass of the first user. That misses the point that hash values must be different for each user and each pass entry.
I suggest to use the date of registration of a user (for example) as salt. This way for each user and each pass the hashing algorithm will be different (ok, if two users have the same pass AND the same reg. date it will be the same).
Or maybe you can use user id for salt, or some combination between user id and reg.date and user name.
Edit:
Your approach is actualy better than hashing with known algorithm without salt, but worse than hash+propper salt.
What you do is just applying custom hash function of your own. That can't be easyly brute-forced without knowing the custom algorithm, but is vunerable to other attacks.
And I suggest not placing a table with name "SALT" in the db, for if DB is hacked the attacker wii get the passwords AND the salts for them.
This question already has answers here:
Secure hash and salt for PHP passwords
(14 answers)
Closed 8 years ago.
I have read tons of questions and tutorials about encrypting a password, and while I've learned a lot, nowhere did I find an answer to this.
I want to use crypt() for hashing a password that I will store on Database. I also know I need to use a salt so it works properly, and I've read that the best way to generate a random salt is by using this or something similar.
If I understood correctly the process is this:
User enters a password
Random create a salt
Hash password and salt
Store result in database
But then how do I recover the salt when user tries to login?
User enters his password
I somehow add his own unique randomly generated salt
Hash both of them together
Compare it to hashed salted password stored in Database.
In a few questions I've found, one of the answers was to store the randomly generated salt on the database. But I thought the whole purpose of salting was to be more secure, if an attacker got access to my DB he would see the 'salt' fields and even if my passwords are encrypted he would gain easy access to accounts.
Other answers said that the 'salt' is prepended to the password when using crypt() so there is no need to store it in a separate field. My question is, how do I get access to it? Is there some function that does this and I'm totally missing?
You store the salt in your db, along with the hashed password, i.e. hash(salt+password).
If your database gets compromised and someone gets all the hashes and the salts, they cannot run a rainbow table attack against your hashes - they will need to brute force each hash. With a good hashing algorithm, the brute force attack is unfeasible.
What is a rainbow table attack?
Lets assume a generic hashing algorithm, hash(f).
I, as an attacker, precalculate common passwords (f) and their hashes (hash(f)). Now, when I get your unsalted database of hashes, I just need to look through your database for hashes that match my precalculated table (rainbow table).
For example, if my rainbow table stores that for f = qwerty, hash(f) = someRandomHash, I look through your database for someRandomHash and as soon as I find it, I know that user's password is qwerty.
However, if you salted your passwords, when a user set his password as qwerty, you calculated his hash as hash('saltqwerty), which means, you did not calculate his hash as someRandomHash but instead as someRandomSaltedHash. This renders my rainbow table completely useless.
I am left with no choice but to brute force your table. I know the salt, but I don't know the password, so I have to calculate hash(salt+password) for every possible permutation and combination of password. With a slow enough hashing algorithm, this can take centuries (worst case).
How do you login a user?
User submit his user_id and password. You query the database for the salt for that user. Then you compute hash(salt+password) and compare against the hash stored in your database.
You can safely store a hashed password and a salt in the same database - the idea is that since the salt is different every time, even the exact same passwords will be stored differently in the database, which virtually eliminates brute-force lookup weaknesses associated with things like md5-encoded passwords.
Out of an obvious mass confusion, if you're able to use PHP v5.5.0 or higher, password storage has become remarkably easier with the use of password_hash and password_verify.
As an additional benefit, these functions don't require you to have separate password and salt fields in your database - you can simply store the returned password_hash value and use password_verify with the clear-text password to validate.
I don't know a lot about high level security DB, but how about this?:
hashedPassword = hash(UsurID+GivenPassword)
So, at logon time, youget first the User Login, and his ID, and then the given password to compare with the hashedPassword tha is already in DB.
As I said, I dont know if this will increase security, but at least it makes all passwords differents, doesn't?
Anyway, I'm still learning too.
I was wondering if there was a method to change the way my site hashed passwords. My coder friend wasn't the smartest when he didn't add salts to the sha512 hash. So now it is very insecure and I wish to change that. I was thinking about making some complicated code to rehash when someone who has the old hash type logs in and it would set the variable to true after adding a salt. Or I could take the currently hashed passwords and somehow fuse a salt into them. I would rather not reset my user database if I don't have to. Any idea would help. I am also quite the php noob so please explain if you include code.
It is Hashed using this method.
<?php hash('sha512',"passwordhere") ?>
Alter your user table to include a 'salt' column, default value of 'NULL'.
Alter your login code to check if the user has a salt:
If yes, compare the salted hashes and log in
If no:
Compare the unsalted hashes.
Generate a random salt.
Generate your salty hash.
Store your new salt and hash in the database.
Continue the login process.
Of course, you will also need to update your code for registration, password change/recovery, etc.
Alternatively, instead of a 'salt' column you could put in a 'hash_ver' column and use that to determine which validation method to use and when to update the hash. That way if you wish to use a hashing method that packs the salt in with the hash like bcrypt you don't get stuck trying to figure out what type of hash you're dealing with.
Every password-storing-system must have the option to switch to a better hash algorithm, your problem is not a one-time migration problem. In the answer to this question i tried to point out the necessary steps.
Note: Fast hash algorithms like SHA-* are not appropriate to hash passwords, instead switch directly to a slow key-derivation function like BCrypt. The new PHP function password_hash() will make hashing easy (it will generate a safe salt for you), and is "future proof", also it will make switching in future possible.
$old_hash = hash('sha512',"passwordhere");
$salt = ''; // Generate salt here
$new_hash = hash('sha512', $old_hash.$salt) ;
I understand that bcrypt is more secure than other methods but still puts you the same situation where you need to salt passwords!
If the salt is included in the hash string it's not needed to store it separately in the DB. Everytime I need to create a new hash, meaning a new salt as well, do I have to get all the passwords, extract the salts and check the new one doesn't exist already against my DB passwords?
Wouldn't be easier to store directly the salts separately for easy compare? If yes then I don't get:
the point of storing the salt in plain text
why bcrypt is more secure than manually use sha256 with salted passwords
I'm actually going to disagree with Curtis Mattoon's answer on a couple of things.
When you hash using bcrypt, the salt is stored directly inside the hash, so you don't need to store it separately. I'm not sure what he means by not having to store it at all, because the hash without the salt is completely useless. The salt is needed to verify the password against the hash.
I agree on this point. If you are updating one password, you don't need to update them all. In fact, it would be impossible because you (hopefully) don't know the passwords for any other users.
You don't need to go through pains to get a unique salt. If that were the case, you could use uniqid, but the problem with that is its output is predictable. Predictability is a bad thing in cryptography. Instead, what you want to do is use a pseudo random salt as close to random as possible (i.e. using /dev/random instead of /dev/urandom). If you have a billion users, you may get one or two that have exactly the same salt, but seriously, is this such a big problem? All it does is doubles someone's chance of brute forcing the password for those two particular passwords out of a billion, and I doubt it's even that high of a chance of a collision occurring. Don't strain yourself over this. Make the salts random, not unique. Using things like last login time or IP address is only going to take away from randomness.
As for a comparison between SHA512 and Blowfish, see here SHA512 vs. Blowfish and Bcrypt
This site seems to do a decent job at a brief explanation: http://michaelwright.me/php-password-storage
Quick answer:
1) You don't need to store the salt.
2) You don't need to update all the hashes, if you use a unique salt for each password.
3) I'm no crypto expert, but when you're using a unique salt for each user/password, an attacker would have to use a different set of rainbow tables for EACH user. Using the same salt value across the site means that every user's password would be susceptible to the same hash tables. In the past (for better or worse), I've used a function of the user's last login time and/or last IP as the for their password's salt.
e.g. (pseudocode) $password = hash(hash($_POST['password']) . hash($row['last_login']));
4) I'll defer the "Why is bcrypt better?" question to someone more knowledgeable about such things. This answer may help: How do you use bcrypt for hashing passwords in PHP?
I've been looking at PHP's crypt function and a few questions on Stackoverflow, and I'm trying to figure out salted and hashed passwords.
I found this on the PHP community page:
<?php
function md5crypt($password){
// create a salt that ensures crypt creates an md5 hash
$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
.'abcdefghijklmnopqrstuvwxyz0123456789+/';
$salt='$1$';
for($i=0; $i<9; $i++){
$salt.=$base64_alphabet[rand(0,63)];
}
// return the crypt md5 password
return crypt($password,$salt.'$');
}
?>
How does something like that compare to:
<?php
// Slightly modified example from PHP community page
$password = trim(mysql_prep($_POST['password']));
// Get the hash, letting the salt be automatically generated
$hashed_password = crypt($password);
?>
Here's an excerpt from another question:
However, the PHP crypt() function can
use a variety of different hashes to
compute the hash. When you prefix your
salt with "$1$" you get a hash with an
MD5. When you prefix with $2$ you get
a crypt with blowfish, which is more
secure.
The "$1$" is prefixed to the output so
that the hash can be verified. If it
wasn't included, there would be no way
to know from the stored hash which
algorithm should be used! This
information would have to be stored
elsewhere. To save you this trouble
PHP includes the algorithm in the hash
output.
My head is spinning a bit concerning hashes, encryption and salts... but the part that really stumps me, is how do I compare a user-entered password against a salted hashed password, if the salt is randomly generated upon user creation... and not stored--and on top of that, what's the point of using crypt() with an automated salt, if you HAVE to specify the correct prefix to be able to validate the password again upon user return?
You need to store the salt with the user.
The purpose of the salt is to ensure that two users with the same password get different hashes.
This prevents rainbow table attacks.
EDIT: Your salt should contain (cryptographically-secure-)random bytes.
Right now, you're restricting it to only contain letters and numbers
The idea is to have a random salt for every user/password.
Adding a salt will just make more difficult to guess your password, but using a random salt for every account will increase the security as it'll reduce the way for an attacker to guess any other passwords, as given some current and unsecure password and/or username, the reverse engineering to guess password would be easy.
It has a big impact on cross-system security as people tends to use the name username/password on most sites.
Using a random salt makes an attack almost impossible with a dictionary as you'll need to compute every salt possible to guess any password.
If you look closely at the format of /etc/shadow, you'll see the nomenclature in the second field (with : delimiting fields):
username:${enctype}${salt}$HoPeFuLlYVerYloNGpassWOrDhAsh: ... ... ...
The salt is actually stored with the password. {enctype} is the type of encryption being employed, {salt} is the salt. Since you know the encryption type and salt, you can naturally reproduce the hash with the password they provide (thus authenticating the user).
A handy table of {enctype} values for crypt (for informational purposes):
ID | Method
─────────────────────────────────────────────────────────
1 | MD5
2a | Blowfish (not in mainline glibc; added in some
| Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)
And finally, how PHP lets you use them.
So, if you see a string like:
root:$6$foobar$JKLsdiuoilI/KSJHDKUyjh/SHDKJyUYW(....)
You know that you're dealing with SHA-512 and the salt is 'foobar' (and likely, the account is foobar too!).
It is (one) example of how salts are stored and associated with hashes. As SLaks said, don't restrict the salt to just ASCII. At the minimum you should be obtaining bytes from a PRNG or HRNG, falling back to time() only when no RNG is available.
No, You are doing it wrong. Use solardesigner's PHPASS in order to do the hashing and validation. Finally, never EVER use your own ad-hoc scheme, doing that is asking for trouble.