For security work should use secure function to save password like hash in php.
When convert password to hash it is not Reversible, therefore if a person forget password, how get password?
Gmail or other account how sent your password?
As noted by Sneftel above, Gmail does NOT send you your password if you forgot it. Any system that does has a serious security issue.
The correct way to handle this is via password reset, under the assumption that you have the user's email address, you can send them a time-limited link to allow them to reset the password. (I.e. When the user clicks the link from their email, this counts as proof that they are the legitimate user requesting password reset). This technique is fairly common in the industry. However if you are an email provider (I guess you are not), then you need alternate means to do password resets such as mobile phone verification. For the love of God please don't do secret questions, they have known security issues yet some big players (Apple) continue to use them.
You shouldn't ever have to reverse a hash, that is the point in storing them like that. Perhaps give the user an option to reset their password but avoid sending them out their current password. If it is essential this is done, then you will need to store them plaintext or using some algorithm you have made to encrypt them.
Related
For a website which stores passwords hashed with the password_hash php function, I was thinking of the following way to enable users to reset their passwords, but I did not know if it caused any security breach:
User fills form with their email/username combination
Form retrieves this user's hashed password and sends it by email
User fills form with their hashed password, and their new password
Database is updated with new password
This seems to ensure that only someone with access to the account owner's email could change the password
Emailing the hashed password exposes this in plaintext over email. While a strong hashing function prevents brute-forcing, it is still susceptible to dictionary attacks and the like. So, if an attacker were to intercept the email they might be able to determine the password.
This is especially troublesome knowing that many users reuse passwords across different services. Also, such an email can remain in the users' mailbox for a long time. This means that the security risk could remain for years after the user successfully resets his/her password.
A much safer alternative is to use a one-time random token (which you will of course need to store somewhere in the database), ideally also limited in time: this ensures only the recipient of the email can reset the password while avoiding the risk mentioned above.
We all know we shouldn't be storing user passwords as plain text on
the database. However I have seen some sites that have implemented
a send-forgotten-password feature. So if I ask my password, I type
my email and they send the password.
Note: I'm not talking about a password change (http://sample.com/forgot_pass?token=ddm39fhksnc)
How do these sites achieve it? They store plain passwords on their
databases (maybe a different database) because as far as I know you
can't reverse a password hash to the original string it was built from...
Is there anyway this feature can be implemented securely? Or I should
convince clients to stick with forgot-pass-link method.
Thanks.
If they are able to send you your password then they are storing your password in plain text.
Note that you can find out the original password from the hash if a deprecated hash function was used (like md5).
There is no way of doing it securely. If your database gets breached the attacker will be able to read out all the passwords and corresponding email addresses/usernames. If your users re-use the same password for different sites (which most people do) what can happen.
Even if there would be a "secure" way of finding out the password from its hash, what stops the attacker from doing the same?
Such a feature cannot be implemented securely. If the application can retrieve the original password (e.g. from an encrypted password), a successful attacker can retrieve the passwords as well. That's why one should use a hash function like BCrypt, SCrypt or PBKDF2.
Another weakness is sending the password at all per e-mail. A better way is to send a token, and let the user choose his own password after confirmation. The same code can be used to register a new user and to reset a password.
You open the door to major security issues if you store the actual password in the database. But if in fact you must resend their password to them, one way you could do it, is when they register, store the password in a text file located outside of the public directory.
Then create some sort of naming logic that associates the record to the text file. And then from there, make it so the only way you can access that text file is with the proper security checks in place, and then via your script.
My solution is adding two field in table "user" in my database: "token" field and "expired_time" field.
When user send a request to reset password, your application will update token string and expired time to reset password for that user.
Send an email with link has username (or email, or id,...) and token like http://example.com/resetpassword.php?id=userid&token=token
In resetpassword.php, you will check authentication by userid, token and in expired time (maybe 5 minutes)
Allow user to change their password.
This is my solution, I hope it'll helpful :)
When a user wants to do a password reset, an email is sent with an unique URL so he can reset it. Like this:
website.com/forgot.php?email'.$email.'&hash='.$thehash
$thehash is a unique hash for every user stored in the database.
The problem is that $thehash is stored in the database just the way it´s used in the URL. That´s just as stupid as storing the passwords in plain text. If someone get´s access to the database it doesn't matter that I have my passwords stored with sha512 and a secure salt, the attacker can just get access to all account using the values (email and hash) all found in the database and change passwords for users.
When I hashed user passwords the user had one part of information that could not be found in the database, the plaintext password so it worked out. But now, I have no idea what to do since I have nothing unique not found in the database. So what is a good way solve this? How do I securely store hashes?
The problem isn't with how you're storing hashes, it's with how the reset link works.
You don't want to use the hash to authenticate a user for password resets, for the reasons you mentioned.
Use a perishable token instead. Whenever a user requests a password reset, generate a token (256-bit should be enough) and store its hash in your database, along with the user who requested it, and the token creation datetime. Put that token in the reset link (instead of the email+hash). When the user clicks the link, your server will receive the token, find the corresponding user and it'll be safe to change the password.
By only storing the token's hash in your database, but using the unhashed token in the email link, you're making sure that even if the attacker still has access to your database, he won't be able to forge his own reset links.
By comparing the time when the user clicked the link with the datetime stored when the token was generated, you'll be able to control how long the reset link is valid (and avoid situations where a user forgets to delete the email, gets his email account compromised, and have the attacker use the reset link).
Check this Authlogic Password Reset Tutorial for a full implementation.
When a user wants to do a password reset...
I will refer you to the OWASP Forgot Password Cheat Sheet, which in essence states:
1 Gather Identity Data or Security Questions
2 Verify Security Questions
And an alternate to giving the users a hash of something:
3 Send a Token Over a Side-Channel: "After step 2, lock out the user's account immediately. Then email or SMS the user a randomly-generated code having 8 or more characters... It is also a good idea to have the random code which your system generates to only have a limited validity period, say no more than 20 minutes or so... Of course, by all means, once a user's password has been reset, the randomly-generated token should no longer be valid..."
Allow me to add here that you can email the user the original token, but store a hash of it in the database using exactly the same protections you use for normal passwords, i.e PBKDF2/BCrypt/SCrypt, and storing only the resultant hash in the database. Then when the user uses the password reset email, if it's still within the very short time window, take whatever they give you, and use your password_verify() function to compare it to the reset token hash.
4 Allow user to change password
Thus, your reset tokens are protected by:
Only being issued upon a validated request
Only being valid for a few minutes
i.e. hopefully too short a time for someone who's stealing your database backups to be able to use them!
Optionally being protected from rogue database access by your password hashing mechanism, just like any other password.
Your reset tokens are obviously not protected from an attacker with access to the user's email account, or who can change the listed email account, while the token is active.
Password reset via security questions as a whole is obviously not protected from an attacker who knows or can compromise the security answers and who has access to (or who can change) the user's listed email account.
#relentless is correct. If the attacked gains access to the database isn't it true that he/she would be able to reset the passwords regardless of whether they had the keys? You're also assuming they've either gained access to the user's e-mail account or guessed the hash entirely. Another thing to consider, you don't necessarily have to store the hashes in the database. Consider this: let's say the hash is created by combining the user's e-mail with a key you've previously determined. When the reset page loads simply rehash the e-mail and key and see if it matches the hash in the query string.
Why don't you pass $thehash as a session variable, then check it to the function your directed to 'if it is set?', if it is, then execute, after then delete the session variable.
How do I securely store hashes?
...
So what is a good way solve this? How do I securely store hashes?
This is the "Unattended Key Storage" problem, and its a problem without a solution. See Peter Gutmann Engineering Security.
John Steven of OWASP provides one of the better write ups related to password hashing and storage. He takes you through the various threats and explains why things are done a certain way. See
Password Storage Cheat Sheet
Secure Password Storage Threat Model
There are multiple posts on the Internet regarding this issue, but here's how I see it.
(Do correct me if I'm wrong in what follows...)
A hacker can only do permanent damage if your actual DB and login credentials get known/compromised, where the data can be changed. Otherwise, the data remains safe even by changing the email address in the URL. Just as long as you don't give a potential hacker a back door to change the Email address; that's gold in its own right.
If passwords are properly stored using a one-way irreversible hashing method, then they are just that; irreversible and chances are rather great that they cannot be put back together. If a user's password has been compromised, then that will be a red flag for you to re-think the way you're using your DB.
At best, even if a user's password gets changed, give the user a method to change it again, then set a column to track how many times it has been changed. If it keeps changing too often, then again that will be another red flag. I have used a similar method to what you're using now and nothing got changed in the DB even when changing the Email address in the URL; everything must match.
Plus, even if someone did change a user's password, depending on what type of permissions or access you've given your users, what's the hacker going to do, change the password again?
The URL should contain the Email associated with the account, the hashed key stored in the DB and then retrieved, and will only work if a hacker has gotten hold of the user's Email account credentials and has gotten access to what should be a unique link.
I don't know which hashing method you're presently using, but there are a few that many suggest using.
crypt()
bcrypt()
scrypt()
PBKDF2
PBKDF2 on PHP.net
PHP 5.5's password_hash() function.
Other links:
PBKDF2 For PHP
Footnotes:
Quoting owlstead if I may: (which I do agree with)
"The best methods are PBKDF's such as PBKDF2, bcrypt and scrypt. crypt should not be used if possible, password_hash() is an implementation of crypt and bcrypt and not a separate algorithm. Users passwords can always be compromised if they choose a bad password. One way cryptographic hashes or PBKDF's cannot be reversed, but they can be brute forced (e.g. using a dictionary attack)"
Just trying to hack together a simple script, and I had a little question about passwords.
Is there anyway I can send someone a random password that they cannot see themselves but can use to say, change their facebook password to in order to block themselves from logging in? I will then send them the visible password at a specified time later on.
This is for purely educational purposes, as I'm just building little apps here and there to learn php and mysql.
Example: Friend wants to get off facebook for 3 hours. He uses web app and I email him a randomly generated password for him to change his current FB password to. However, on the email it is hidden to him. After 3 hours, he gets another email allowing him to use it.
I understand there might be some easier ways / clearer methods of achieving my end goal, but I am just curious about this itself!
Thanks so much
If you are sending an e-mail that contains "something" that allows the user to log in with, you are sending them a password and if it's clickable/copyable from the e-mail, they will see it. Regardless of if the password is plain text that directly matches a stored value (like "thi$ismyPa$$word") or some other encrypted value that when inputted is decrypted to match a stored value is irrelevant, the user either way knows what that value is (because they have to enter it). In order for the user to provide a value, they have to have the value. As others have mentioned, you could implement a one-time use password into your application, but that wouldn't work for a facebook implementation because it's not your app and you can't control it's functionality. The short answer, if you provide something to the user (like an e-mail) that is used to access a system, then they can see the value(s) necessary to login.
The traditional approach is to calculate a hash sum of some kind from the password, and send that. Thre are one-way algorithms, like MD5, that can do this. That way, conformance TO the password can be assured, without having to send the password itself, or from which the password can be inferred.
For even greater security, both a hash and a checksum can be sent: that way the hash itself cannot be intercepted and sent as a proxy for the password: authentication will not happen unless both the hash and the checksum values agree.
I currently use,
base64_encode() to encode a user's password, this works well because it allows me to simply use base64decode() to decode the password to a word and send to there email if they lose there password.
I have been reading up on password though and a lot of people seem to say that you should use sha1() to encode a password. I am all for improving my system's security but if I convert to use shal() then I will not be able to send a user there lost password.
What do YOU use? Can you give me some advice? And is there a way to decod to a readable password to email a user?
As I typed this question I just remebered that some forums do not send you a password when requested but instead send a special link to re-set your password, I am guessing that this is because they are unable to decode your password maybe?
//what I use now
$password_encoded = base64_encode($password);
//what I am considering using
$password_encoded = sha1($password);
Please, please for the sake of your users do not store their passwords in any reversible format! It doesn't matter if it's Base64 encoded or triple-DES 168-bit encryption - if it is reversible, it is exactly as secure as if you didn't encode it at all.
No website that has any interest in protecting itself or its users (or has a lick of sense) will send a user their password via e-mail. The only thing we can do that's even remotely close to secure is to send users an email with a unique, one-time-use link that lets them set a new password.
Store a hash (bcrypt or PBKDF2) of the password which has been salted
Throw away the original password as soon as you've hashed it. Excise it from memory.
Always require the user to create their own new password over an SSL channel
Trying to get by with anything else is honestly just negligence. Let's use a very common scenario used in security discussions:
User Frederic's email is compromised. This could be from leaving his computer unlocked or using a weak password. Regardless, an unauthorized person has access to his messages. Ideally, this would mean nothing more than some embarrassing love letters read by a stranger. Unfortunately, the unauthorized person discovers a forum will email Frederic's password in plain-text. Like most users, Frederic uses the same password for everything, including his online banking. His username is listed in an email from his bank. Now the situation is very unfortunate.
Users are placing trust in you when they create a credentials-based relationship with you. Part of that trust is that you will keep those credentials as a secure secret between you and them.
Related
A lot of the surrounding issues and ideas have been answered very well on SO:
Difference between Hashing a Password and Encrypting it
Why is challenge-response approach a poor solution for forgotten passwords?
Non-random salt for password hashes
As an administrator, you never actually need to recall the password of a user. You simply need to know if a string they've once submitted, is identical to another.
If a user forgets their password, they don't need to be told their old password, you can simply have them provide a new one.
Since you don't need to know the actual passwords, using a crytographic hash of the words would seem like a safe way to store them. However, large tables of pre-computed strings have been made to easily do a reverse-lookup of the hash back it's original string. These are called rainbow tables.
To avoid easy lookup of pre-computed string, you should salt your passwords before hashing them. The salt can be their username prepended, or their user ID postfixed, whatever extra information you have on the user that is permanent that you can easily add to the password during authentication.
You should let a user RESET a password but never RETRIEVE their password. That is why you would want to use a one-way hash (SHA2) instead of a form of encryption that lets you decode it.
Imagine if you left your email open. I could simply request to retrieve your password for some website, delete the email, and you would never know. On the other hand, if you required me to reset the password instead, the account password would change and the owner would obviously realize that something is wrong. (This is a dumb scenario but the concept is what's important)
Hashes can be "reversed" by trying all possible combinations of words (or using rainbow tables) until a matching hash is produced. One way to avoid this is to append/prepend the provided password with a salt to make it a very long and unpredictable string. The salt should be a unique string of data unique to the individual's account.
In PHP there is no SHA2 functon. SHA-2 is a family of hash algorithms, (SHA-256, SHA-384, SHA-512, etc...)
hash('sha256', 'The quick brown fox jumped over the lazy dog.');
An absolute must-read on this topic is Jeff's own You're Probably Storing Passwords Incorrectly. Here's the executive summary:
Do not invent your own "clever" password storage scheme.
Never store passwords as plaintext.
Add a long, unique random salt to each password you store.
Use a cryptographically secure hash.
Base64Encode offer no security, because anybody can reverse it easily.
If you absolutely need to reverse the password, a good way is to use a secret question, and to use the answer as an encryption key. Once the password is encrypted, you throw the answer away (you do not store it). You also use the standard sha1 encryption for the time when you need to verify that he enter the right password. If the user want its password, he enter the answer to its secret question, and you use that to restore the password and send it back to him.
It's not as secure as hash based encryption only, but if you need to send back the password it's a good compromise.
You may want to look at the mcrypt library for php http://ca3.php.net/mcrypt
I always delete my account only any sites that emails me my password. I put too much effort and time into memorizing long random passwords to have it sent to me in plain text.
Use sha1() or higher non-reversible hash to identify the password. When authenticating a user password, retrieve the hash, and compare it with the hash of the password supplied during authentication. If they match, then the user is authentic within reasonable standards.
$user = "joe";
$password = 'password';
$saved_hash = DB::Query("select hash from users where username = ".quote($user)." LIMIT 1");
if (sha256($password) == $saved_hash) User::authenticated();
Never, ever send passwords in email. Send a unique, non-predictable, generated key, such as in PHP:
$key = sha256(time().rand().$secret_seed);
Send this key to the client, for one time use, to set a new password.
You will want to use a hash(preferably sha1) with "salt"
You can do the hashing on the server when authenticating in one quick query:
SELECT * FROM user WHERE password = MD5(CONCAT(?, salt));