Question

The Question:

How can I verify who is resetting a password without requiring security questions, D.O.B, or any other parameters?

The Context

On many websites, when a password reset is requested, a random hash is attached to the username in a database. This hash is sent as part of a URL in an email to the user. When the user clicks on the emailed link, they are sent to a page where they can choose a new password. The problem here is, the user can type in any email address on this "Set New Password" page, and set a new password for that account. So how can I verify that a user actually owns the account to which they are setting a new password?

I figured that the URL containing the random hash should be sent as a parameter along with the new password, because the password can then only be set when the hashes match. However that doesn't work since the $_GET['hash'] variable only exists on the set password page, which was linked from the email. As soon as the user clicks "Submit," the $_GET['hash'] variable has disappeared.

The simple solution would be to pass the $_GET['hash'] variable AGAIN through the URL on Submit, but that creates an extra step for the developer, and might confuse them. (I am creating a library, so my code must be simple enough for a developer to understand and integrate).

How have people tackled the problem before? Some people have suggested to make the reset link time-limited. This would help, if say the link was only valid for 30 minutes, then that means a malicious user could only change someone elses password if that person requested a reset in the last 30 minutes. However, there is still a window of vulnerability there, so it's not perfect.

Please ask for clarification if needed.

Thank you

Was it helpful?

Solution

Only the correct user will click on the link in the email.
You can pass the hash in the form where the user enters the new password:

$hash = $_GET["hash"];

...

<form name="newpasswordform">
...
<input type="hidden" name="thehash" value="<?php echo $hash?>"
...
</form>

This way you can reverify the hash when the form is submitted.

OTHER TIPS

I've done (not saying it's the most elegant solution, but it works :P):

Send email with url like http://mysite.com/resetpwd.php?code=1234&email=hello@hi.com, with code being a hash of the user's current email and hashed password.

User clicks link, code verifies that "1234" is the hash of "hello@hi.com" and the hashed password, then shows the password reset page, making sure to add "1234" and "hello@hi.com" as parameters in the form passed to the next page. When they click enter, it sends to like http://mysite.com/resetpwd.php?code=1234&email=hello@hi.com&newpass=hellothere123

Resetpwd.php checks for $_GET['newpass'], and if found verifies again that 1234 is the hash of the user's hashed password and hello@hi.com, then resets the password.

Edit: oh, I see, you don't want to pass the verification code again...ignore this then, unless I come up with a better solution :)

What i've seen some sites do to achieve that extra level of security is to make you specify a security question and answer. So in addition to the hash, you would match up the security question ("what is your favorite pet?") and now you have confirmation it is the user.
It's probably about as secure as you're going to get without implementing other security measures like bankofamerica.com does, where they have you pick a picture, along with a question, etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top