7

Most password reset systems involve emailing the user a one-time link that lets them reset their password. The token needs to be in the URL, as most email clients do not allow HTML emails to perform POST requests, and asking the user to retype the token is not an acceptable experience. However, this puts the token at risk of leakage through the referer header.

One potential solution to this is to avoid any external links on the password reset page. However, most sites have a standard template that does include external links (Facebook, Twitter, etc.) and not using this template would make the page look odd - and potentially make users think it is a phishing site.

It seems browser vendors are aware of this issue and some browsers support the meta referer tag, which can be set to "never" so the URL is never leaked. However, not all browsers support this tag, so it is not a complete solution.

So, how do you create a password reset process that does not have this leak?

paj28
  • 32,906
  • 8
  • 93
  • 130

3 Answers3

3

The first option, which I have seen used in practice is exactly that which you seek to avoid. Don't include the token in the URL, but provide an instruction to the user to copy and paste it out of the email and into a form field on the page that is linked.

If that is not an acceptable user experience, I would suggest that the link containing the token be a non-interactive interstitial instead. The link will send a user to a resource that takes the token off of the URL, stores it somewhere else (a cookie, session state, whatever works for you) and then 30x's the user forward to the real, interactive "forgot password" page that no longer has the token in the URL. This method has an added advantage over the method suggested by several other answers (invalidate token on page load) in that you can continue to use the same token for some reasonable period until the form is submitted, so if the user forgets, or closes the page accidentally, they can simply re-enter the process from their email, rather than having to start over at the beginning with a new forgot password request.

Xander
  • 35,616
  • 27
  • 114
  • 141
3

Browser leaking links?

Here is a screenshot of my chrome settings:

chrome settings

You can see that the browser may:

  • query another service about whether the link is legit
  • query another service if the link has an error

I don't know the specifics, but that means you also have to worry about those services leaking the token before the user has a chance to visit the page or in case your webserver is misconfigured.

Password reset page

  • If you do not want to link referer information, do not include the link.
  • If you want to mitigate some effects, include a strong CRSF token in <input type="hidden"> ; that way even if the link is compromised, they still need a valid CRSF token.
    • Why not also require a cookie?
  • If, by any chance, you are using github to host your website code, do not put your config (e.g. value of SECRET_KEY used to generate tokens) online.
dnozay
  • 211
  • 2
  • 2
2

Since it is a one-time link, just invalidate the original token and generate a new one on the page (make it an invisible field in the form), then POST it with the password reset form.

Also, do not add any extra information that may leak user identity in the email link. A SHA-256 token is enough to complete the password reset process.

Alexander Lee
  • 81
  • 1
  • 3
  • This solution won't guard against leakage in the case where a user navigates to the password reset page using a link with a token, then does not submit the form. – Max Heiber Nov 30 '16 at 19:44
  • 1
    @mheiber The original token is invalidated on the first visit to the reset page, A new token is dynamically generated within the page and POSTed with the form. So if the user navigates away, nobody gets the new token and it eventually expires. This can also be done in other ways of course, but this is one way to do it. – Alexander Lee Nov 30 '16 at 19:58