Currently I have the following set-up for handling users that forgot their password.
- A user types in his/her e-mail address and presses the forgot password button.
I look up the user belonging to that e-mail address and I store a new 'forgot password request' in the database. The forgot password request item looks like this:
Guid ForgotPasswordRequestId; Guid UserId; DateTime ValidUntil;
I generate a token to identify the forgot password request by converting the ForgotPasswordRequest Guid to a Base64 string. The Guid is a version 4 Guid (random, not time or MAC address based). Check this MSDN link for notes on the implementation.
I create a link like
www.example.com/account/ForgotPassword?token=TOKEN
which is sent to the user in an e-mail.Whenever someone visits that link within 24 hours he/she can set a new password for that account.
I think the chances of someone guessing the token is small as a Guid is a 122 bit number (128 bits, minus 6 bits for version information). So a hacker would need to try, on average, (2^122 / 2)
tokens within 24 hours before succeeding. If my math is correct that is 3 * 10^31
tokens per second, which I'm sure my server can't handle ;). Also the token they need to guess is in no way related to the user they wish to reset the password for.
However, is it correct to generate the token directly from a generated Guid? Is there anyway that using a Guid and not a secure random number generator makes an attack feasible? Is there any other problem in this scheme that makes it unsecure?
I've seen this question, although its related it doesn't explain best practices for generating the token.