How do I implement a password Reset Link
here are 2 alternatives using HMAC or JWT (which i think provide better, more secure, email URLS)
- https://neosmart.net/blog/2015/using-hmac-signatures-to-avoid-database-writes/
- https://www.smashingmagazine.com/2017/11/safe-password-resets-with-json-web-tokens/
Create a table that has a structure like
create table ResetTickets(
username varchar(200),
tokenHash varbinary(16),
expirationDate datetime,
tokenUsed bit)
Then in your code when the user clicks the reset password button you will generate a random token then put a entry in that table with the hashed value of that token
and a expiration date of something like DATEADD(day, 1, GETDATE())
and appends that token value on the url you email to the user for the password reset page.
www.example.com/passwordReset?username=Karan&token=ZB71yObR
On the password reset page you take the username and token passed in, hash the token again then compare that with the ResetTickets
table, and if the expiration date has not passed yet and the token has not been used yet then take the user to a page that lets them enter a new password.
Things to be careful about:
- Make sure to expire the token, don't let a email from two years ago reset the password.
- Make sure to mark the token as used, don't let other users of the computer use the browser's history to reset other users passwords.
- Make sure you generate the random token safely. Don't use
Rand
and use it to generate the token, two users who reset at the same time would get the same token (I could reset my password and your password at the same time then use my token to reset your account). Instead make a staticRNGCryptoServiceProvider
and use theGetBytes
method from that, the class is thread safe so you don't need to worry about two threads using the same instance. - Be sure to parameterize your queries. In your current code if I typed in the userid
'; delete dbo.[USERS] --
it would delete all the users in your database. See the linked SO post for more info on how to fix it. - Be sure you hash the token, your
passwordReset
page only accepts the unhashed version, and you never store the unhashed version anywhere (including email logs of outgoing messages to users). This prevents an attacker who has read access to the database from making a token for some other user, reading the value that was sent in the email, then sending the same value himself (and perhaps getting access to an administrator user who can do more stuff than just read values).