* Not being very careful with the lifecycle of a token.
* Encrypting tokens and expecting users to feed back the same encrypted token, and failing to authenticate.
* Simple parse errors and SQL injection on the tokens themselves.
* Exploitable generation (for instance, non-cryptographic RNGs) for the tokens themselves.
* Having multi-page flows starting from the receipt and validation of a reset token, and then having standard web flaws somewhere in that flow (for instance: userid is validated only at the start of the flow).
* Mishandling of cases where users have multiple outstanding reset requests.
* Accepting the email address to send token to from web user, validating the address, and then using the user input directly as the email address to send the token to; as in: systems that will send token to user@real.com;attacker@evil.com.
One bug everyone has in their password resets: they don't cancel outstanding tokens when users change their passwords, so that long after a user has reset their password, their email boxes still contain password-equivalent tokens. That's not a high-severity bug, but it's a meaningful one.
* Accepting the email address to send token to from web user,
validating the address, and then using the user input directly
as the email address to send the token to; as in: systems that
will send token to user@real.com;attacker@evil.com.
I'm missing something here... How does "user@real.com;attacker@evil.com" validate as "user@real.com"? Is this a regexp vs strcmp() issue or is there something more subtle at play?
One scenario I can imagine is a regex which doesn't properly handle multi-line inputs (quite common issue in ruby[1]). Together with a mail header injection vulnerability, this input could be dangerous:
Total speculation, but maybe they're trying to be clever and accept things like "John Doe <john@doe.com>" as being equivalent to "john@doe.com" and end up using a full e-mail parsing library for the matching which is more capable than they realize?
> * Accepting the email address to send token to from web user, validating the address, and then using the user input directly as the email address to send the token to; as in: systems that will send token to user@real.com;attacker@evil.com
If you do a "is this even a valid email?" check and a "exists user by email" check with that input (assuming no SQLi, of course), would this even be possible? I'm failing to see what the vulnerable code would look like in that scenario.
> One bug everyone has in their password resets: they don't cancel outstanding tokens when users change their passwords, so that long after a user has reset their password, their email boxes still contain password-equivalent tokens. That's not a high-severity bug, but it's a meaningful one.
This is solved by simply deleting the tokens after reset, correct?
You can get expiration and many other nice things without having to worry about a whole class of other issues.
To make a password reset all previous reset tokens, simply include an autincrementing number for "passwordVersion" and stick that sucker in the HMAC as well.
> If you're saving a token in the database to delete, you're doing it wrong anyways.
I think the strength of your statement here is not warranted – in the context of security, there's no flaw from doing that. Likewise, saying "HMAC" is "the right way"... well, I wouldn't agree with that.
If you do HMAC, you only have time-based expiry. Thomas was talking about tokens sitting in email inboxes that are still valid and are effective passwords... you can't make your HMAC tokens expire as soon as they're used, so that's still a concern.
The top "disadvantage" discussion in that thread is about somebody messing up their links because they rolled their own base64 encoding with period characters in it ... or something like that. I'm not even sure what they were thinking, but there's nothing about keeping reset tokens in the database that would prevent their problem.
Strong disagree. You are much better off saving tokens than you are in using HMAC or any other cryptography to try to extend your security boundary to email. There is more that goes wrong even with simple HMAC tokens than there is with opaque random tokens.
Can you shed some light about what could go wrong?
I remember reading about this HMAC/"no database" technique and thinking it was pretty cool.
Is it because you may want to encode more fields than just expirationTime, but also (say) lastLoginTime and such, so the GET URL would get awkwardly long (and possibly break in some email client), or is it something more fundamental than that?
Cause I thought that using the HMAC as a primitive was the right way to get hash-based authentication right, as opposed to messing around with actual cryptographic hashes.
If you have to validate, you're doing something wrong (but this is a something wrong people do sometimes do). You should send email only to the string you saved in the database record for the user.
There's no reason you couldn't have the user pick a new password before you send them the token. Just don't activate it. Leaking the reset token in this way looks unlikely, but there could be other vectors... like an attacker poisoning the sites DNS cache to intercept reset emails, or a state or database disclosure bug in your code.
It's fairly common to see reset tokens going in to the database verbatim, instead of treating them as passwords and stashing away a hash (single SHA is fine if your tokens are long and random).
There is a reason not to do this: at the point where you cache the new password, you have no idea who's making the request. An attacker banks a trivial password into the password reset, triggers the email reset token, and waits for the unsuspecting user to click the link in the email. So you have the user enter the password again after clicking through the token. But now you have a condition where accounts are only as safe as it is difficult to get users to type an attacker-chosen string into a web form.
Hmm, can you explain how this opens up new phishing vectors?. Sure, you could dress the reset page up like a promotion with an iframe and try and get the mark to enter a 'coupon code' or something, but that isn't going to work without the reset token. Password resets by email are already vulnerable to carefully timed phishing.