Automatic completion of passwords in web forms allows attackers to grab your password if an XSS vulnerability exists.
We don’t usually associate XSS vulnerabilities with compromised passwords, but it is sometimes possible to steal login credentials through XSS vulnerabilities on a website. Take a look at the example attack below.
- Find any XSS vulnerability on a domain.
- Use the vulnerability to load the login page into an
iframeon the vulnerable page.
- Wait for credentials to be loaded into the form by the browser or an extension.
- Leverage the Same Origin Policy to obtain values from the login form in the iframe.
The example is demonstrated on this page.
Similar approaches have been described before (see some links below this article), but I could not find any solid advice on how to mitigate this type of attack.
These are some options developers have to mitigate the attack described above.
- Don’t allow login-screen when already logged in
Always redirect your login page to a different page when the user is already logged in. That way, the attacker cannot simply include the login page, the login form won’t be displayed, and the browser won’t automatically load the user credentials.
- Don’t allow framing of login page
EDIT – As pointed out by avlidienbrunn in the comments below, X-Frame-Options is not a solid solution to mitigate the attack. It can be circumvented by abusing the Same Origin Policy by initiating a new window instead of using frames. The paragraph below is therefore not accurate.
Similar to the solution above, the developer can set the header
X-Frame-Options: Deny so that the login page cannot be included in an iframe by the attacker. See the mitigation in action here (tested to work in Firefox).
Firefox, for example, is vulnerable to this type of work-around. It displays credentials on a domain-name basis, meaning the credentials will also get inserted in a form that isn’t on the login page.
If we look at Chrome, it surprisingly shows that it’s protected against this whole class of attack by not allowing password fields to be accessed whatsoever. The demo above seems to have no effect on Chrome. (Side remark: I have difficulties forcing Chrome to remember credentials, so wasn’t able to test the demo thoroughly.)
My last example is LastPass, which has its very own approach to remembering credentials. It offers url rules to link urls to login credentials but links login details to exactly one page by default. This effectively disables any XSS from grabbing the password on a page that isn’t the login page. Only an XSS vulnerability on the login page could then be used to obtain the secret, drastically reducing the attack surface.
Finally, I’d like to take some time to advocate the use of passwordless logins (I strongly suggest reading it). Passwords are and will always be a weak link in security. They get stolen, through any of so many possible attacks, and users often don’t care to change them or maintain an extensive (safer) set of different passwords. Then why not opt for a type of login that eliminates the need for better password management by reluctant users and undoubtedly keeps them safer in the long run?
The following comments originally appeared on a different blog and have been copied here for reference.
X-Frame-Options won’t protect against this as you can open a new window and do the same thing. The only real protection against this is to use autocomplete=”off” or emulate the same functionality in browsers that doesn’t support it.
@avlidienbrunn, that is true , I didn’t think of the new window cross-domain possibility. However, the autocomplete=”off” is not a solid solution, because it appears to lose support for several modern browsers, if this source is to be trusted: http://stackoverflow.com/a/3868314/436953
Yeah, seems browser devs thought it would be a good idea to remove the feature. However, the same functionality can be achieved by using type=”text” and styling it into a password field with CSS. Another thing you could do is to use a nonce in the password field’s name. That way the browser won’t recognise the input 🙂 Anyway, I just wanted to point that out and also chip in a say that the “open new window method” works in Chrome too. However, it requires a click from the user to get around popup blockers in some scenarios.
Thanks for your additions. I like the obfuscated type=”text” trick. Although I have a feeling that password managers like LastPass are able to recognize the login form, regardless of how random/”noncy” the input field’s name attributes are. I may be wrong.