My database stores unique salts for every user.
I'm creating a login script in php for an application where each user has it's own unique salt and here's how I plan to implement the login.
User enters details and sends them
Username is sent and script check if it exists
If it does then returns the salt for that user otherwise general error is returned
I need the script to return the salt for that user because otherwise how would my app verify that the submitted password is correct when it cannot hash the password without the salt and send it back?
Now here's what I'm unsure about. Does it matter whether the salt is encrypted or not because a hacker could just see what it is and see the password hash and maybe could do something with it. Should I encrypt the salt before I send it?
Maybe I'm not understanding/overlooking something in the replies below.
Advice needed please.
It doesn't matter if your salts are hashed or left as plain strings - the important point is that salting a password prevents the direct use of dictionary/rainbow table attacks to brute-force crack passwords. An added advantage is that each user has a different hashed password as a result.
Salts are randomly generated string that are created server-side and don't involve any kind of transmission to or from the browser.
On your server:
// Password from form
$pw = $_GET['password'];
// Generate salt using unique values
$salt = (rand(8).$registration_date.$username);
// Password to be hashed
$pwthb = ($pw.$salt);
If a hacker gains access to your databases, then your game is over in the majority of cases as you need to store the initial random salt to hash it for comparison.
A simple example:
User enters initial password in browser upon registration
On your server, password is combined with a unique salt, hashed and stored as password in DB
Salt is stored in DB
Note: hashing can be done using PHP or using MySQL/DB functions
When the user returns:
User enters password in browser
Grab salt from DB and combine with the password entered
Hash password+salt and compare with stored/hashed password
If they match: authenticate
In terms of further reading, It's probably worth looking over the following:
Is encrypting a salt value with a password/plaintext a viable alternative to straight up hashing?
The necessity of hiding the salt for a hash
How store salt in distributed environment
Related
I have a database with accounts that still use the MD5 algorithm which is old and unsafe, so I wanted to update the passwords with the password_hash function in php.
I made a login for users with a md5 password so they can be prompted with an update field to update their password. It all works and I see the new hash string in the database. But when I want to login using their new password it's just not possible.
I use a PDO update query to update the passwords, does anyone have a solution or know if this is even possible?
Thanks in advance,
Bram.
EDIT:
This is the code I use to verify the passwords.
if (password_verify($password, $rowofusers['passwordhere'])) {
//code here
}
As mentioned, the correct way to do this can be completely transparent to the user and should not require an "update password prompt".
When the user tries to log in take the following steps to modify your login process accordingly.
Check if the hash in the db starts with $2y$ to determine if the password should be check with md5 or password_verify. If it does start with $2y$ then just use password_verify and ignore the remaining steps (continuing on with the rest of your normal login process).
If the password hash in the database does not start with $2y$ then first, check the plain-text password against its md5 hash.
If the plain-text password's hash doesn't matches the md5 hash in your database continue with normal failed authentication process and ignore the remaining steps here
If the plain-text password's hash does match the md5 hash in your database then take the plain-text password and run it through password_hash and update your database with the newly generated BCRYPT hash from password_hash.
You would have to keep this code in your login process until all passwords in your database have been updated and no remaining md5 hashes are left. The user will never know that their password hash is updated and never be prompted to enter their password twice as it's completely unnecessary.
At the moment, my system is using a custom generate salt when the user registers which is then stored in the database along with their hashed password.
Now, I was thinking about having an option for users to define their own salt on registration. For an example, if they visit register2, they see 3 inputs:
Registerpage:
Email
Password
Custom Salt
So they fill out their email, password and set a custom salt-- whatever they want to be, in the limits of the hash function
$loginhash = hash_hmac('sha256',$password,$userdefinedsalt); //just for the post don't use
now, because they user has generated their own salt, that salt doesn't actually store in the database, only the hashed password.
Now the user has registered, every time they want to login, they must specify that custom salt they have created that hash with, use a POST get the inputs, hash them together and compare the passwords.
So if a malicious hacker somehow finds a way in to the database, they will have a useless hashed password, and no salt, therefore rendering that password useless? Yes or no?
Now, if another user doesn't feel like doing this, they can go the route of the system generated salt, that stores in the database etc.
Does this seem fesable for protecting users passwords?
What if a user forgets their salt?
They can go to the password reset, which will generate a custom hashed password with a salt, they can then login, and again perform the actions of creating another password with their salt, when doing so, it deletes the computer generated salt from the database to leave that blank.
Is this just asking for a world of hurt, is this a bad way?
It's the purpose of the salt, to prevent an attacker from getting all passwords with one single rainbow-table, nothing more nothing less. So better let the salt do its work and do not mix up different goals. Letting the user choose his own salt could even hurt security, because the user could choose a weak salt, which is not unique or is too short.
Asking for a user defined salt is just like asking for a second password, you wouldn't do that, would you? You could increase security this way, but then i would use the second password to encrypt (two-way) the calculated password-hash.
Better in my opinion is when you define a server side strong key, and use it to encrypt the password-hashes. Then the attacker cannot brute-force the hashes, until he gets additional privileges on the server to read the key.
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.
A client has a huge userbase and I'm required to encrypt/hash passwords in a secure manner. The problem is I can't ask every user to change their password and the passwords are already hashed with md5() without a salt. One way of doing this is to encrypt the current passwords with a salt and when a user changes or resets the password i just encrypt it with the salt.
Are there any pitfalls or more or less obvious dangers of doing so [ i mean sha1(md5(password) with salt) ]?
Thank you for your time
Add a new field to the user table for storing the new securely hashed passwords - for this, please do something safe involving per-user salt and multiple rounds. Check what other people are doing (ie., bcrypt) instead of rolling your own.
When doing a password check, if the newPass field is null, use the old password lookup, but urge users to do a password reset once authenticated.
Modifying the current (old) password scheme to be hash(perUserSalt + existingPassWordHash) should work fine.
if you plan to use sha1(md5(password).$salt) it's all right.
You can use this system even further. No need to take any special action when user changes a password. Just encrypt it the same way: sha1(md5(new password).$salt)
It depends on what attack you are attempting to defend against. If the attack is someone viewing the database, then you could use a symmetric encryption method (like AES) with a key defined outside the database. Using this method requires the authentication procedure know the encryption key and you update all the rows in the database by encrypting the hashed password with the encryption key.
If the above is not an option, you have a problem. ;) The problem is that right now you don't know what any user's password actually is. All you have is the hashed version. Your routine for verifying a login is to take the input supplied by the user, hash it, and compare the computed hash with the stored hash.
Your option would be to store the old hash and create a new field to store the new algorithm. Then as people log into the system, perform the upgraded salted-hash and delete the old hash. This will work as you expect, but if a person never logs back in (or changes their password) they will never upgrade to the salted version of the hash.
My personal opinion is to use the AES encrypted option since that prevents the casual viewing of hashed passwords and it covers all the passwords in the database.
I have a classifieds website, where everybody may put ads of their products.
For each classified, the user has to enter a password (so that they can delete the classified whenever they wish).
So basically, when somebody wants to delete a classified, they click on the classified, click on the delete button, and enter the pass.
I use MySql as a database.
I use this code basically:
if ($pass==$row['poster_password'])
where row[poster_password] is fetched from MySql...
What do you think?
Thanks
See this: Secure hash and salt for PHP passwords
Hash their password (maybe with some salt) on the way into the database. Store their hashed password in the database (NOT their actual password). Then fetch their hashed password from the database and hash their input password and compare the hashed passwords.
Some lame pseudo code:
password_hash = hash(password_cleartext)
# store password_hash in database
Later:
input_password_hash = hash(input_password_cleartext)
fetched_password_hash_from_db = fetch(db, password_hash)
if (input_password_hash == fetched_password_hash_from_db) {
... authenticated ...
}
For a start with php, try: http://php.net/manual/en/function.sha1.php
Your code looks safe, but your design may need some work.
SQL Injection
The dangerous part of the code is in storing anything in the database, or showing anything to the users, that is collected from the user. So, the part you have to be careful with occurs prior to your example. Ensure that you're validating, filtering, and escaping any data that you collect from the user, including the password and the ad information.
Encryption
The advantage of storing the password in the database is that you can let the user retrieve the password via email or some other means if they lose it.
However, if you do store passwords, you should store them encrypted, using a secret key, so that if someone is able to direct read access to your database, they can't read all the passwords in plain text. Still, you're going to have to store the secret key somewhere, and if someone gets your secret key and has access to your database, they will have access to all of the passwords.
Hash Values (recommended)
It's best practice and more secure to only store one way hash values (SHA1 or SHA256) of the passwords in the database instead of the actual passwords. This way, you cannot retrieve the password. Hash values are intentionally one way by throwing away some of the data.
Instead of retrieving the original password, you hash the password that the user enters and compare the hash value against the stored hash value to see if it matches. If the user loses the password in this case, instead of emailing the password to the user, you email the user a new, randomly generated password.
Storing only the hash value protects your data even further, since even if the user has read access to your database, the hash values offer no advantage, and there is no secret key that will unlock all of your hash values.
When you hash the passwords, be sure to use a random salt value and store the salt to protect your list of hashes against rainbow attacks.
Summary
Sometimes you don't get to choose the password. Sometimes the password comes from another system, so you don't always have a choice, and sometimes your superiors (maybe even the users) will demand that they be able to retrieve passwords, however, when possible, you should choose the more secure option.
Note that all of this encryption and hash value business only partially protects your server against people who are able to obtain read only access to your data. Sometimes, getting your data is enough of a prize, so if the user can read the password hash, can they read your credit card numbers?
You need to protect your database. Do you have a secure password on your database system? Do you only allow local access to your data? Have you created a database user with least privileges to use in your application? Are you properly protecting yourself from SQL injection and scripting attacks?
If someone has read and write access to your data, the whole password business becomes moot.
Don't store the actual password in the database. Instead store a checksum (MD5, SHA1, etc). When you want to compare, perform a checksum of the value the user submits and compare the checksums.
That way you never have the actual password in memory.
Best practice is to keep a salted sha1 hash in the database:
if (sha1($pass.$row['poster_salt'])==$row['poster_password'])
(poster_salt is a random string generated and saved when the user chooses the password.)
That way if an attacker gets access to your database, they still won't get the passwords of the users (which are probably used elsewhere too - most people don't bother to choose different passwords for different sites).
Also, you should use secure (HTTPS) connection. And require sufficiently strong passwords.
(At least if you want good security, which might be an overkill in the case of a simple ad listing).
I would encrypt the password before storing it, then decrypt when retrieving it so you can check it against what the user entered in plaintext (per your example code above).
Also, protect yourself against any SQL injections, or someone could see all the passwords (and other data) in your database.
This implies the passwords are placed into your passwords unencrypted. If this is the case you should be using some sort of encryption when entering the passwords. One way of doing this is the MD5 function which hashes the password.
When doing the insert you would do
Insert into table(email, password, whatever) values('$email', md5($password), whatever)
And when comparing you would do
if (md5($pass) == $row['password'])
You should hash the password somehow and store and compare using the hashed version. See this link for more details:
http://phpsec.org/articles/2005/password-hashing.html
my suggestion is the following
the users table have two columns, one called "password" and the other "salt"
$password = 'youruserpassword in plain text';
$salt = bin2hex(openssl_random_pseudo_bytes(32));
$passtostore = hash_hmac('sha384', $password, $salt);
insert into users(password, salt) values($passtostore, $salt);
Then to verify if the user has entered the correct password...
retrive both password and salt from the database and
if(hash_hmac('sha384',$userpass, $row['salt']) === $row['password']) {
// is valid
}