I'm working on developing a Strong Algorithm to reset passwords securely and looking for feedback from the User Community. Here's what I've come up with so far (with help from What are best practices for activation/registration/password-reset links in emails with nonce)
Password Reset process works as follows: When a User requests that a "reset password link be emailed to them"...
- Generate a $salt
- Prompt the user for the $email address they want to have their "reset password" link sent to.
- Retrieve a $key (=secret user-predefined sensitive account data that only they know such as the city they were born in or SSN#Last4)
- Create $nonce = hash($email . $key)
- Save to table:
- $nonce (PK)
- $salt
- $exp_date
- Create $hash =hash($salt . $email . $key)
- Email the user a link to reset their password @ URL=...?hash=$hash
When the User clicks on the link we sent them, it brings them to a form:
- Enter $email
- Enter $newPassword
- Confirm $newPassword
- Prompt for Key Field... ie: "Enter the City you were born in:" Enter $key
When the User submits this form...
- Retrieve $hash from the URL
- Recreate $nonce = hash($email . $key)
- Use $nonce to retrieve $salt from our table (if unexpired).
- If hash($salt . $email . $key) == $hash from URL, then the Validation is GOOD!, so we... Update the user's password in the database
- Otherwise, we refuse the attempt to change the password
Notes:
- All $email and $key responses are trimmed & lower-cased before processing to avoid confusion.
- Regular maintenance task sproc should periodically remove all expired nonces to keep the table clean
What do you think?