Is Your Site Leaking Password Reset Links?(robots.thoughtbot.com) |
Is Your Site Leaking Password Reset Links?(robots.thoughtbot.com) |
It's worth noting there are a number of reasons this JavaScript could possibly not execute beyond people who have JS turned off. I've seen a number of sites fail to execute JavaScript when an Ad Blocker is run, for instance.
In this case, there are a number of server side fixes available that wouldn't require any JavaScript. They're not terribly complicated and will always work. For that reason, I'm still comfortable with the server side fix, but think the JS fix is a decent alternative.
The ones that don't are most likely bots (now even that's changing thanks to projects like phantomjs).
I feel like I've seen more of the former than the latter.
Before generating the PW reset link, someone might try to login first. So they'd enter bob@example.com into the login form and then when that failed, it's not uncommon to redirect with error-msg-in-session to /login?email=bob@example.com . So you'd leak the email first.
Sometimes this is actually something I as user want to have, since it might be that I'm receiving the email on device A, but want to reset the password on device B.
And please keep the password reset tokens sane. If you are not encoding some data into the token, you don't really need that 80 character random string for security.
Tradeoffs...
Again this is far from ideal, but also not readily exploitable by attackers that couldn't already access the data.
I've even had a situation where I was on my desktop machine and clicked a reset link on the web site. I realized I didn't have my email set up on that machine yet, so I went to my phone and did it from there. In your scenario, this wouldn't work. That seems problematic.
My web site's visitors are only from my universty. Only to those who have METU email addresses. It is easy to log in to a web mail from the browser. Password reset is not a something done on daily bases. It is okay for my situation. Not very user friendly but it is a bit more secure.
In fact the idea come from this; what if a student fills registration form and sends the validation email to his teavher. And the teachet, without reading click, in other words validates the registration process mistekenly. Now, I have a criminal case (I shouldn't allow Professor Naughty Elizabeth to be registeted for example) against me! I wanted to protect my ass. And I used it too in password resets.
But this is sad: http://caniuse.com/#feat=referrer-policy
[1] - http://www.w3.org/pub/WWW/Protocols/HTTP/AsImplemented.html [2] - https://tools.ietf.org/html/rfc1945
"Browsers will not send the Referer for resources fetched via HTTP from a document loaded via HTTPS"
So using HTTPS resolves the issue? But breaks analytics?
Any further clarification would be nice, thanks!
For instance, someone places Google Analytics in the head of the default layout for a given site. Now traffic to and from the password reset page, which uses that layout, is being recorded. This means an attacker would only need to gain access to that account, which is probably much less guarded, and gather referrers containing password reset tokens. From there they could quickly try the last few--which might still be active--and easily gain access to one or more accounts within the site.
So "that account" you mention, is it the Google analytics account or the web application (leaking urls) account? Why is it much less guarded?
This is a valid concern, though it's worth noting that you shouldn't be including 3rd party content you don't trust on any potentially sensitive page in the first place. This includes not only password pages, but potentially ANY logged in page on the site.
Otherwise, you should consider the 3rd party content trusted and move on.
Once a reset link has been clicked, it should be immediately invalidated.
So unless the server was able to respond to the link and provide the analytics stuff but not somehow invalidate the token, I can't see how this is a problem.
Another related problem is that some third party mailers move all their links via URL redirectors. In that case there's a chance the host application fails and the link is left valid.
I'm not sure about this... Couldn't this produce some unexpected reset failures in cases of browsers preloading links in webmail clients?
Besides, it would be an odd security hazard if browsers/webmails preloaded links in emails (malicious URLs in spam/scams).
edit: in Drupal, the reset link loads a page with a button that the user must click on. This avoids issues with potential preload or anti-virus scans.
So my first thought is returning a page with no external requests (render on the srrver) which isn't very dev friendly.
My other thought is returning a redirect to a page with a token derived from the original token and the clients IP or some other fingerprinting information.
Most frameworks provide some form of storage (whether server-side or client-side) that is tied to a specific session, so you can use that to remember the fact that the current session recently used a valid password-reset token for user ID 123.
Or you could use a similar mechanism to put the token in a hidden <input> after redirection, so that it gets submitted again when the user types in their new password.
Exactly. Submitting tokens via GET requests (as is necessary for an emailed token) should be handled in the same way as POST (POST-redirect-GET): the resource which validates the token should not be the one that presents the "password reset" form.
This is a good one in specific. In general, be very careful of what information you share with who. Information is dangerous, and it leaks all over.
Without a valid token, the reset form shouldn't load. Problem solved.
I did consider this approach for Clearance and intended to go with it, but was discouraged from doing so after hearing reports that some enterprise email AV does things like open some links in emails.
There is also the user experience concern that a click the link in my email, do something else, then click the link again, having forgotten I already clicked the link. Now I'd have to re-request again.
Also, this approach is impossible if you use HMAC tokens.
I don't think anyone who opts for this approach is wrong but like most things, it's a tradeoff.
I think you should invalidate a token whenever a user enters a new password and submits a form (hence POST).
But some sort of token needs to be used even after clicking the email link because the "enter a new password" form needs it posted as well (to prevent people from using that form willy-nilly on any account).
So, for single-use tokens, you're probably OK for passing it in the URL (e.g. myhost.test/resetpw?token=abcdef), but it is usually considered a bad idea to use the URL for non-single-use secret info. Once it hits the server, the full URL may be stored in log files unsecured or if you use SSL termination before the server, it could be logged in other places as well. Additionally, the user's browser itself may store your secret URL in the history.
They are good for 1 password reset, not 1 page load. It's possible to make them good for 1 page load, but most I've encountered are not due to the tradeoffs that would involve (see other discussions).
I'm grumpy enough to suggest not loading them period, but I'm a curmudgeon.
BTW, why would the URL that identifies the reset request need to be unique if the tokens have enough entropy?
1. You include a script such a TypeKit. The typekit deliverable itself is not owned, but bad actors have access to typekit.com logs.
2. You use a smaller third party add on service that itself uses a logging service such as PaperTrail. PaperTrail is hacked, providing attackers access to logs.
3. You reference no external assets, but your site contains external links in the footer. Users click the navigation links rather than completing the form. You have leaked the token to whatever site that is. You are at the mercy of their log storage. YES, this does actually happen. User's click crazy things.
As I mention in the article and in other comments here: this is not likely to be exploited. Fixes, however, are not too difficult. Even adding the not-quiet-fully-supported `meta` tag to your head is a good start.
If I read this article today, I'd think, "That's interesting. let me make a note to check that out." It's not a hair-on-fire security situation, but it's not "not a problem at all" either.
You use a piece of open source software that has a javascript file which the author has hosted on a CDN. In order to mitigate an attack where someone changes the content of the javascript file you use a hash[1] to ensure the file does not change. You think you are safe, but a malicious actor gets access to the CDN and instead of changing the file, instead builds a quick scripts that looks for password reset referrer patterns and races the human to reset the password first. A computer is probably going to win that game that majority of the time.
Would be nice to set a body though, wouldn't it? Also, not allowed by HTML.
Of course I'm not suggesting you're not allowed to use any javascript on your site, or even that you should only use it when it's strictly necessary, but if it's entirely unnecessary and you don't engage in best practise by, for example, using progressive enhancement, then that's something that could be improved.
I might not be using the right term here, but the general idea is that you create an encrypted token out of some data and verify that the data is unchanged and still valid on the server. In that way you can provide a token that ensures the user had access to the link you sent them, but you don't have to store it in the database.
Loading the page without clicking does not invalidate the link.
I agree this is not highly secure. It's basically one notch above sending cleartext passwords by email (which many websites unfortunately still do).
Using an addon like NoScript it's possible to selectively enable javascript per domain. When a website doesn't work without js I am forced to decide whether it's worth enabling js for this site. Very often I decide it's not worth it and I never use that site again.
No way am I going to allow JavaScript from every single site using CloudFlare to run all at once.
If your browser instead presented the JavaScript as a program itself, and listed the programs it executed, and from what sources, users would have a wholly different perspective. JavaScript has the illusion of remote execution; most users don't think of it as executing programs on their computer.
Addons like NoScript are essential security precautions that mitigate a host of attacks. Unfortunately, even security-essential software like the Tor Browser Bundle leaves JS enabled by default because it'd "break" the web.
There's other reasons---as a free software user and activist, I won't run non-free JavaScript programs.
I gave a talk earlier this year about these problems and some ideas to solve them: https://media.libreplanet.org/u/libreplanet/collection/resto...
Sadly doesn't work in Chrome.