Password reset by email without a database table
The normal flow for resetting a user's password by mail is this:
- Generate a random string and store it in a database table
- Email string to user
- User clicks on link containing string
- String is validated against database; if it matches, user's pw is reset
However, maintaining a table and expiring old strings etc seems like a bit of an unnecessary hassle. Are there any obvious flaws in this alternative approach?
- Generate a MD5 hash of the user's existing password
- Email hash string to user
- User clicks on link containing string
- String is validated by hashing existing pw again; if it matches, user's pw is reset
Note that the user's password is already stored in a hashed and salted form, and I'm just hashing it once more to get a unique but repeatable string.
And yes, there is one obvious "flaw": the reset link thus generated will not expire until the user changes their password (clicks the link). I don't really see why this would be a problem though -- if t开发者_运维百科he mailbox is compromised, the user is screwed anyway. And there's no risk of reuse, since once the user's password is changed, the reset link will no longer match.
To remedy the obvious flaw
, add the current date (and more time-related info representing current fraction of a day if even a day is too long) to what you're hashing to generate the mystery string and check it -- this makes the string "expire" (you may check the previous as well as current date or fraction if you want longer "expiry"). So it seems to me that your scheme is quite viable.
If someone accessed your database with password hashes, they would not know the actual passwords. If you implement this system, then they can generate the reset links and reset the passwords themselves. With random strings and knowledge of a compromise, you can invalidate all the random strings, and only users in the process of resetting the password would be compromised even without knowledge of the access. Not a likely scenario, but it might be worth considering given the nominal overhead of random strings.
Actually after thinking about this again, your method is potentially less secure than "The normal flow".
If you just send back HASH(HASH(user's original password))
, I can see scenarios where this can give an attacker leverage:
Scenario 1:
Jim
registers on your site asjimjones@microsoft.com
.Jim
requests a password reset, but doesn't use it. The reset email is left sitting in his inbox for eternity.Jim
changes his email address on your site.jimjones@gmicrosoft.com
is compromised byBob
.Bob
now runs a bruteforce attack via his distributed GPGPU farm and recoversJim
's password.
Scenario 2:
Jim
uses a the passwordjimjonesupinthisma!
for his banking account.Jim
registers on your site asjimjones@microsoft.com
.jimjones@microsoft.com
is not in any way associated withJim
s bank account.jimjones@gmicrosoft.com
is compromised byBob
.Bob
now requests a reset, he now hasHASH(HASH(jim's password))
.Bob
now runs a bruteforce attack via his distributed GPGPU farm and recoversJim
's password, which he then uses to accessJim
s bank account.
Scenario 3:
(Your site uses TLS, users register via TLS.)
Jim
registers on your site asjimjones@microsoft.com
.Bob
requests a password reset onJim
s account.Bob
works for NSA at Room 641A.Bob
uses his global internet sniffer and obtainsHASH(HASH(jim's password))
as it's emailed in plaintext tojimjones@microsoft.com
.Bob
now runs a bruteforce attack via his distributed GPGPU farm and recoversJim
's password.
Variants of scenarios 1 and 2 happen all the time (depending on how strong the hash and password are), I'm not so sure about 3. The point is, your method leeks unnecessary information, which can indeed leverage an attacker against your user.
I suggest you use randomly generated tokens that have nothing to do with the user's password.
let's say on a very rare case, two of your users had the same hashed password even after concatenating random salt to it; there would be a problem right? I guess it wouldn't hurt if you add email or Hashid of user_id to the reset password link.
Just passed by this issue and have an idea:
1) Issue a JWT (Json Web Token) with info about user account. The token has an expiration, say 1 hour.
2) Send the token to the user in an email/link
3) User clicks the link, the token is sent to the server endpoint, the token is validated. If valid, you unpack the token and updates the user account
Any flaws in this approach? No database is touched (except for new user passwords if necessary)
精彩评论