Best practice for resetting forgotten user passwords - plaintext

As far as I can think, there are two reasonable ways to reset a user's forgotten password.
Have the user enter their email address and a new plaintext password is sent to their email address.
A link is sent to their email address which has a UID number in the URL. Clicking on this takes the user to a form on the website where they can choose there own new password.
Which method is preferable and why?
If method 1 is used, perhaps a third party could read the email and obtain the new password.
If method 2 is used, what is to stop someone methodically going through UID codes to try and access the form to change a user's password?

The best pattern would be :
User requests password reset. Best is to do it through username, and
don't indicate if the username exists or not (to avoid possible
users listing through a script)
You generate a record in a new database table with userid, datetime
of request (= current datetime), and a GUID you just generated
You send a mail to the user, pointing to password reset page with
the GUID (not the userid) as parameter
On this page, you should check that the GUID is existing, and
eventually you could put some expiration date (=the user has 1 day
to reset, for example)
Don't forget to mark the record as "used" (with an extra field in
the table) when the user reset his password, so that you can stop an
eventual second try...
It could possibly even more secure, but that is already quite good I think....

OWASP has a good checklist of https://www.owasp.org/index.php/Forgot_Password_Cheat_Sheet
Here is a quick summary of steps:
Gather Identity Data or Security Questions
Verify Security Questions
Send a Token Over a Side-Channel
Allow user to change password

Verify if the sender is the real user by asking verification questions.
Do not send password on the personal email that is not on the planate employees list.
Do not add the word "password" to the title or body of the email.
Make sure to send separately the username and password.
For Office 365 user, direct them to the forgot my password area or send this link https://passwordreset.microsoftonline.com
Don't get intimidated by the user, escalate to IT manager if the need arises.

Related

Password reset via mail

I am doing a web application using Eclipse EE. I have a module which is supposed to reset user passwords and sends the user (via email) a link to a page where they can reset the password. Any insights please?
The main steps would be:
Provide a "forgot password" page where the user can enter her email address
look up the entered address but don't tell the user any details. Don't output a message like "email address not found" as it would allow a malicious user to look up valid email addresses. Better give them a message like "you'll receive a link to reset your password if the entered email address is registered".
Create a strong unique random identifier to associate it to that reset-request. E.g. use a cryptographically RNG provided by the framework and combine it with something unique like e.g. a GUID.
Store that unique identifier along with that reset-request in e.g. a table in your database and put a timestamp to that record. That's important as you'd want the user to be only able to reset her password within a fixed time frame.
Send an email with that unique identifier put as a query parameter in a link to your application. E.g. https://yourapp.com/pwreset/?requestID=7392af1747ce3781
Fetech the requestID parameter at your pwreset-controller and look it up in your database. If the request comes in within a reasonable time frame based on the initial request timestamp, then let the user reset her password.
Delete successful request-records from your database, so that a sent pw reset link can only be used once. And periodically delete expired records.
Use this as a starting point. As I'm no crypto expert, you may one have a look at this approach ;)

Best practices for forgot password function via REST API

I am trying to find the best practices for forgot password functionality via sending a link to reset password i.e. sending an email with a one time token to the registered user. The token will be stored in the database and when the user clicks the link, we check the token and allow the user to set a new password.
Best practices while designing forgot password function -
The token must be unpredictable, that's accomplished best with a
"really" random code which is not based upon a timestamp or values
like the user-id.
Like a password, the token should be hashed, before storing it in
the database. This makes them useless for an attacker, even if the
database is stolen.
The reset-link should preferably be short to avoid problems with
email clients, and contain only safe characters 0-9 A-Z a-z
(base62 encoded)
The token should have an expiration time within single-digit hours.
The token should be marked as used,after the user has
successfully set a new password.
When a user changes their password or requests another password
reset, expire all tokens already associated with their account.
These are some of the points I found. What can be other security issues that should be considered ?
Sources:
Secure password-reset function
Ycombinator News
A couple other practices I've seen:
Check user is on the same machine/browser/IP as the one where the reset password request was triggered (unless it was initiated by admin/system).
Rate-limit number of reset tokens that can be generated for an account.
It should also be noted that the best practice is usually to use an established library rather than inventing your own mechanism, as too many things can be overlooked.
I have the same question and found the OWASP Forgot Password Cheat Sheet.
Also few things that I would like to add:
Usually if user entered non existing email sites anyway shows message "pwd restoration link was sent". This is due to prevent hackers from determining that user with the email exists in system. But IMHO it's better to say user that email is not exists because usually it may not remember email used during registration.
It is better to add some additional personal question to user like a birthday date. If hacker stole user's email it makes harder to receive reset link. But since reset link may be sent to user by site admin the question with birthday must be on change password page which is opened by link.
Hackers may automatically send a lot of letters to some user. Some sites uses a CAPTCHA near email field to prevent this.
After successful changing of password all active sessions should be closed and user must be logged out. Thus even if hacker is logged in he will logged out.
It is a good idea to hash a restoration ticket like a password. Here should be used the same hashing algorithms like with password: Argon2, SCrypt, BCrypt.
After user restoration password it is good to mark it a possible fraud and for some time (like a week) do not allow to make some critical actions, like withdrawal money from account.
Also some sites are sending a letter to user that it's password was changed. They do this when user was logged normally changed it manually but maybe it is good to send the same latter when pwd was reseted.

How to get email and username when Facebook registers

As far as I know, on the new Facebook API, there is no way to get the Facebook username. Also, if the user registered to Facebook, his or her account might lack an email address if he or she logged in with a phone number.
However, I am working on a project, where, upon login with Facebook, if the user does not have a user, then the Facebook login is interpreted as a registration. Since, according to my best knowledge, there is no way to get the Facebook username using the API, I am using the email field to generate a username, taking into account only letters.
However, in some cases, the username generated this way is duplicated, or the Facebook account does not have an email address. The best solution I can think about is to redirect the user to a form where he or she can enter the email and/or the username, but that would not help the user-experience.
Is there a way to gather these data without making the user enter them? Or something close to it?
First of all, you should always present the data you want to store to the user BEFORE you store it, and let him change it.
That being said, the (App Scoped) ID is the only thing that is really unique, you can either use the email directly (if the user is already registered, just add the Facebook ID to your database) and present an input field if there is no email - or generate a username with his first and last name. Present the chosen username to the user and let him change it, or tell him that it already exists.
After all, wouldn´t a user WANT to choose his username?
If you want to make it smooth for the user and don´t want to bug him in anyway, you can just store his Facebook ID. Or just use the email directly as username (including the # sign and the domain), as i wrote above. If that´s not good enough, you need to implement your own routine to auto-generate usernames. There´s no general logic from Facebook to do this.

how to track activation link click from correct email address

I am creating user registration page with email activation link in Laravel 5.1.
I send activation link to entered correct email address. How to find activation
link is click from correct email address where I send mail
To give you an idea how this could work:
When user registers generate a per user unique token for the new user (e.g. 60be22f4-e849-4676-b64b-c3493e8709e0)
Save this unique token in your database along with the user name and password
Send this unique token along with your activation email (e.g. as a link: http://my-domain.com/user/confirm/60be22f4-e849-4676-b64b-c3493e8709e0)
When a user clicks this link search for the unique id in your user table and mark this user as active/confirmed.
There's a pretty simple way of doing this:
Store a 'secret' for each user in your database, this should be generated on the first creation and shouldn't change for the life of the user in the system. Secret could be a simple string like 'ajchdu8'
Set up an activation route that contains the user ID and their 'activation signature' like so http://yourdomain.com/activate/{user_id}/{signature}
Create a mechanism for generating and comparing those signatures and use the secret for each user as a way of making user only that user can activate their account (or who ever you give the URL to anyways)
The signature is basically just a hash of things that we know about the user but doesn't change in the database so it could just be a hash of user id and their secret then by providing the user id in the link you can look up in the database the user by the id to get their secret and any other details you require to verify the signature.

What is a secure and efficient method for website users to reset their password?

Many sites implement different methods and I am having a hard time deciding on which method would work best for my site.
My user profiles contain the following data:
username
password (in hash/digest form)
email
I'd like the password reset method to be secure, user-friendly, and efficient.
You should add two fields, reset_code and reset_expiry
This is the process for a secure password reset functionality.
User selects "Forgot password".
User prompted for email/username.
If valid, generates a GUID, and stores it in reset_code and also stores Now()+24 hours in reset_expiry in the database against that particular user.
Then it sends an email to the email address with a link to confirm the password reset. This email would contain a link to your website with the user's username AND reset_code embedded. (This stops a malicious user resetting a third parties password just by knowing their email)
Once the user clicks on the link in the email, they will be directed to your website.
Your website will validate that: the username and reset_code matches, and the current time hasn't exceeded the reset_expiry time.
If all is okay, we can complete the password reset. This can be done by either:
a) Onscreen a new randomly generated password
b) A new randomly generated password via email
c) The ability to enter a password of his/her own choosing
You should not store the passwords of your users, not even in encrypted form. You should only store the hash/digest necessary for authentication. Then, you can't "recover" the password (because you don't know it), you can just reset it, and/or give the user a temporary one-time password that allows him to set a new password.
Update: if you are doing the above, the standard procedure is to have a "require-password-reset" form. The user enters his id (typically his email) and a "token" (eg, a random string) is generated, stored in some table with some expiration date, and sent to his email along with a link to the "password-reset" form. In this form the token is checked, the user is allowed to enter a new password, and instructed to attempt a new login.
Update 2: A small privacy issue might arise: What should we do if the user id (email, user name, or whatever) entered in the request form does not exist in our database? To output a message "User does not exist. Check the id and retry." may be ok, but in some cases it would cause a privacy problem: anyone can check if other someone is registered in your database! If you want to avoid that, you must output the same message ("a mail has been sent with instructions...") even if the user wasnt found (and hence a mail was not actually sent).
Similar privacy issues advise to just output the message "login incorrect : bad user or password" when the user tries to login unsuccessfully - don't disclose if it was an incorrect user or password.
I agree with Leonbloy. Storing the password leads to trouble like the Gawker incident from a few weeks ago (1.5 million userid/pwd combinations were discovered and published).
You should, however, have a "reset password" function that e-mails the new password to the original e-mail address used to open the account.
There should be no provision for changing the e-mail address during the password reset. If the user doesn't have access to the old e-mail account anymore, too bad. Abandon the account and start over.
And use a good Captcha on the reset screen.