I'm designing a password reset system for my website/app right now and I'm not sure if the solution that I've reached could be considered suitably secure. The steps for resetting a password are as follows:
- User visits the login page (HTTPS) and chooses 'Forgot Password'.
- The user submits their email address (or username as the app allows sign-in with either).
- If no account is found with the provided email/username then no email is sent (user is not warned of this to prevent user enumeration).
- A 6 digit number is randomly generated as the reset token and stored in a key-value store (with the key being the token and the value being the user's ID). This store entry is configured to expire after 1 hour.
- The token is sent to the account's email address.
- The user then submits the token onto the same page that they provided their email on (the page contents changes to provide an input for the token).
- If the token is valid then the corresponding store entry is prematurely expired and the user is prompted to provide the new password (with a 'repeat password' input to double-check).
- On submission of their new password, the user's database record is updated to reflect this change and all active login sessions are invalidated.
This system doesn't use the standard method which involves generating a longer token (which comprises of a larger character set than just numerical digits); is this considered insecure?
My reasoning for this method is that our app is being developed for young people (specifically children and teens) and so this password reset system should be as simple as possible. This system means that the user doesn't have to change the page they're on (as the form to provide the reset token is automatically displayed after the email is sent) and they don't have to open any link from the email meaning that only one browser tab is ever used (and it's the same tab).
And from what I can tell, another benefit to this system is that password reset token is never exposed to any logs as it's never included in any URLs, although it's still exposed in the email however that's not something I can get around.
Can this system be considered suitably secure?
Also, would implementing a CAPTCHA service anywhere make this system more secure, or should I only ever consider adding one if we start to see too many requests being made?