-
-
Notifications
You must be signed in to change notification settings - Fork 456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prevent password reset token leak via HTTP referer #707
Conversation
session[:password_reset_token] = params[:token] | ||
redirect_to edit_user_password_url(@user) | ||
else | ||
render template: 'passwords/edit' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
The password reset token is included in the URL emailed to users who request a password reset. When the user clicks the link, they are brought to the password reset form. If instead of completing the form the user clicks a link to another HTTPS resource that may be in the site navigation, then the password reset token will be leaked to that external site via HTTP referer (sic). Taking advantage of this would require an attack to: 1. Control a site that is linked to on the password reset token 2. Capture any HTTP referers that contain the token 3. Use the referer URL to complete the password reset before the user does so themselves. This is a rather involved exploit, but something we should close nonetheless. We address it in this change by requiring that the token be present in the session rather than in the URL before the page is displayed to the user. If the user hits the edit action with a token in the URL, the token will be stored in the session and the user will be redirected to the same URL minus the token. This is a bit more complicated the another change I considered where we simply rotate the token before the form is displayed. While this change is more involved and less localized, it has the advantage of maintaining the side-effect-free `get` (kind of - we do mutate the session).
6f43aae
to
ad294a9
Compare
I like this for the GET safety -- some browsers are eager to optimize GET requests, and mail clients certainly do whatever they want. But I'm not sure if the GET safety is relevant in practice. |
I think it is relevant in practice:
|
Ok, I'm convinced this is the best approach. Any comments on the code itself? |
The code looks good to me. |
Just wanted to note that this is not just for links, but also for externally hosted images and CSS/JS. That means that an image host, CDN or advertisement could possibly hijack this as well. I feel this might increase the attack vector a bit. 👍 for fixing! |
Oh of course. I hadn't considered that. Thanks for pointing it out, @jeroenvisser101. |
A downside of this approach is that the token persists in the session if the user doesn't complete the form and navigates to other pages on the site. If the session is then stolen (perhaps through cross-site scripting) the password can be reset by a malicious user. |
@o-hudson that's correct. We might want to add expiration timestamp on the session (to decrease the chance of it being usable when stolen). |
I had not thought of that. Theft via XSS vulnerability would indeed be a problem, but it's just one of many different problems you'd have as a result of XSS. On thing we could do is add a Controlling the expiration of the session also decreases the window, but as a library I don't want to enforce the expiration on all uses of |
@derekprior For expiration, I'd say we could do this without expiring the session itself (say we'd add
I agree, XSS should be avoided to begin with. (or any way to steal a session) |
I was listening to the older podcast and thought of a different solution for the same problem. This approach may solve it without usage of session or data store.
this way usage of session can be avoided, but requires a |
The password reset token is included in the URL emailed to users who
request a password reset. When the user clicks the link, they are
brought to the password reset form. If instead of completing the form
the user clicks a link to another HTTPS resource that may be in the site
navigation, then the password reset token will be leaked to that
external site via HTTP referer (sic).
Taking advantage of this would require an attack to:
does so themselves.
This is a rather involved exploit, but something we should close
nonetheless. We address it in this change by requiring that the token be
present in the session rather than in the URL before the page is
displayed to the user. If the user hits the edit action with a token in
the URL, the token will be stored in the session and the user will be
redirected to the same URL minus the token.
This is a bit more complicated the another change I considered where we
simply rotate the token before the form is displayed. While this change
is more involved and less localized, it has the advantage of maintaining
the side-effect-free
get
(kind of - we do mutate the session).