Hacker News new | comments | show | ask | jobs | submit login
Secure Account Recovery Made Simple (paragonie.com)
15 points by CiPHPerCoder on Sept 24, 2016 | hide | past | web | favorite | 20 comments



I like Scott a lot but I do not love this post.

He's right: don't ask for security questions from your users. Security questions are ridiculous.

He's wrong about making password reset optional. In 10+ years of consulting at Matasano I can't think of a single application for which users could sign up directly that didn't have password reset. You're asking for a support nightmare by making it optional --- worse, you're putting your engineering team in a position where they can be socially engineered into changing passwords, and this is an attack vector that actually does get used in the wild.

The password reset scheme here is, I think, overcomplicated. If you generate a long random token and associate it with the user's account, there's no significant risk of timing attacks (I'd go a step farther and suggest there probably isn't a realistic risk of timing attacks against tokens either way, but I'd want to confirm that suspicion with some research first). Just look up the reset by the token value, invalidate the reset record (you want to save them anyways), and then check whether the email matches.

If you really, really wanted to be paranoid about it, you could just HMAC the token against a secret you pass in through the environment, so that the attacker can't even map inputs to database entries (in the same manner as they can't meaningfully launch a timing attack against a password hash).

But nerdery aside, unless I'm missing it, this piece seems to be lacking one of the most important controls for password resets:

Invalidate reset records after use, after any password change, and after a fixed (short) amount of time.

It is amazing how many applications have password reset schemes that leave login-equivalent data in people's email boxes for all time.


> But nerdery aside, unless I'm missing it, this piece seems to be lacking one of the most important controls for password resets:

> Invalidate reset records after use, after any password change, and after a fixed (short) amount of time.

That was (somewhat implicitly) covered in the "what incumbent systems" do: https://paragonie.com/blog/2016/09/untangling-forget-me-knot...

Since you mention it, I'll make that a separate list item. It's important enough to risk being repetitive about.


I don't see it anywhere. You should make it very explicit, since it's a mistake lots of systems make. There are popular applications where you can use password reset emails over and over again.

I would say the first most important attribute of a password reset scheme is that it not be based on weak secondary passwords like "Mother's maiden name".

The second most important attribute of a password reset scheme is that it be based on a simple lookup of a random token, and not elaborate encryption schemes, since those schemes tend to cough up game-over auth bypass bugs.

The third post important attribute of a password reset scheme is that they be single-use and rigorously invalidated, so that your application isn't spewing hazmat over people's email spools.



>> ...and this is an attack vector that actually does get used in the wild.

I am starting to think this is the most important thing. Every time I read about an attack or a vulnerability 2 questions pop into my mind.

1. How easy is this to exploit remotely?

2. Is this an attack vector that actually does get used in the wild?

I usually finish both those questions off with "Today and what about next year?"

e.g. It's interesting that quantum computing is going to change quite a few things, but my list of worries is about 1,000 things long, and that's just way too far off to worry about today, or next year.


Yes this is a common tactic to keep compromised accounts.

The attacker compromises the account and generates password recovery tokens.

He then blackmails the user if the user resets it trough support or via account recovery the attacker uses a token to gain access to the account again.

This is a very common tactic in blackmail for online game accounts.

In fact this is also often used to bypass other security controls such as auto account locking.

You compromise the email account, log on the IP or anything else triggers an automatic account unlock the user clears things up with support and the attacket uses the reset token to access the account without triggering a lockout this time around.


The suggestion to make password reset opt-in during signup will never fly. Useful advise starts from the actual behavior of today's users, not the hypothetical behavior of a perfect user.


That depends on your threat model and your audience.

If you're building a typical e-commerce platform, no, it won't. That's why the recommendation is so watered down with "if reasonably practical" and has entire sentences dedicated to "it's OK if you default to Yes, but please give them a choice".

But if you're building the next Silk Road? You should default to opting users out unless they check the opt-in box.


It is really difficult for me to think of an application used by consumers that could sustainably manage password reset as an option, even if the option defaulted to "on". Just having the option would generate an untenable amount of expensive support calls.


> Just having the option would generate an untenable amount of expensive support calls.

I can see the potential for that to be true, but I don't think there's any evidence that this is necessarily true.

Specifically: If you bury the option where only power users (i.e. the kind of users who are likely to use GnuPG and KeePassX) will trivially find it, the sort of folks who never change defaults would leave it enabled.


I am probably missing something obvious, but I am not sure how a timing attack would work during the verification stage (when the emailed token is compared against the database to ensure that it is valid).

If an attacker provides an invalid token, the record wouldn't be found in the database, and the web app would return an error indicating an invalid token. When a valid token is provided, the user is authenticated. You would immediately know whether a token is valid or not—no timing requiring.

However, perhaps there is potential for a timing attack during the initial stage of the reset process, when the user is asking to enter their email address? If the email address provided exists in the database, the server has to 1) generate a token, 2) save the token in the database and 3) send out an email with the generated token. If the email address doesn't exist in the database, the server doesn't have to perform any of these functions.

Potentially, couldn't this allow an attacker to enumerate the email addresses in the web app's database? Of course, in and of itself, this wouldn't allow an attacker to access any of those accounts. And the split-token method suggested by the article wouldn't prevent this enumeration issue.

Is there further potential for a timing attack that I am missing?

EDIT: fixed a typo


I been doing some reading about this in an attempt to answer my own question. It turns out, there is potential for a timing attack during the verification stage. Provided you store the plain text token in the database, an attacker can deduce a valid token by submitting various guesses to the server.

Hashing the token protects against this.

For more detail: http://blog.ircmaxell.com/2014/11/its-all-about-time.html


What's wrong with sending the user a JWT[0] with a short expiration time as their password reset token? For example,

{ "account_id": 12345678, "password_reset_token": "bohghai6fui1Ma7ozaF3nu2PheV2eeroh8daonoh6ceiCub3joengei2Lohhu8ti", "exp": 1474737955 }

Set the expiration to be 5 minutes from the time the token is generated. This leaves open the possibility that the same token could be used to reset the user's password multiple times, but you could avoid that by including the hash of the user's previous password in the token, or by keeping a "password changes" counter in the database and including that value in the token.

0: https://tools.ietf.org/html/rfc7519#page-9 or https://jwt.io


Is there an example of the (specific) timing attack mentioned in the article being exploited?


Whenever I see "base64" mentioned in a security article, I get cautious.

The "split token" password reset is snake oil. Just store the hash of the token (ideally stretched like any password) in the database and mail the original token out. No need for "split tokens". A password reset token is a temporary password and should be treated like one.


> The "split token" password reset is snake oil.

One of two things just happened:

  1. You're being intentionally offensive where it's not really warranted
     by calling this proposed strategy snake oil.
  2. You don't know what snake oil means.
I'm going to assume the latter. Here's the thing:

  - Hash functions are deterministic. You'll make timing attacks more
    difficult, but you aren't removing the underlying timing leak.
  - You database engine almost certainly doesn't compare strings in
    constant time in SELECT queries, so there's almost always going
    to be a timing leak in SELECT queries.
  - Separating the timing leak from the authentication (and making the
    latter constant-time) properly alleviates this risk.
Other solutions (relying on the avalanche effect of hash functions, using a random sleep, or sleeping until a minimum amount of time has passed) are brittle and harder to reason about than solving the problem directly, which is what the article proposes.

See also: http://stackoverflow.com/a/28486617/2224584

You might disagree with the technical details and arguments laid out, but it isn't snake oil.


>> Just store the hash of the token (ideally stretched like any password) in the database and mail the original token out

If I understand it correctly, that's exactly what they propose. You mail the original token out, store its hash. The second string is used as an ID (there should be a secondary index on it).


base64 is just a data storage format and something that is required if you want to push data via GET. They're talking about pseudorandom numbers using a CSPRNG, with appropriate length, that's normally adequate for this scenario.

Can you explain in more detail why base64 makes you "cautious?"

> Just store the hash of the token (ideally stretched like any password) in the database

That's actually LESS secure. Their scheme has an ID (or "selector") and a hash ("verifier"). This means you can limit attempts against a single ID/account and also aren't going to compare a hash entered to every record in that table.

What you're proposing is massively weaker than what they propose. It also has timing attack problems.


Base64 is an implementation detail so it is kind of strange to see it mentioned here. It also obfuscates things so you often see it used in insecure solutions.

That is why the use of base64 makes this look suspect even though on close inspection the ideas are probably valid.


The other post that was linked in the snippet that mentions base64 is far more likely to make people nervous: https://paragonie.com/blog/2016/06/constant-time-encoding-bo...

It's about an implementation of RFC 4648 encoding (including base64, base32, etc.) that doesn't index based on secret data.

Consequently, if a practical cache-timing exploit is ever demonstrated in existing implementations of encoding functions, the open source library we wrote will be immune.




Applications are open for YC Winter 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: