Issue metadata
Sign in to add a comment
|
Security: Credentials API does not require call to navigator.credentials.store to share credentials across subdomain
Reported by
lawn...@gmail.com,
Aug 18 2017
|
||||||||||||||||||||||
Issue descriptionVULNERABILITY DETAILS The Credentials API exposes credentials that were saved by the user on subdomain A.foo.com to subdomain B.foo.com without subdomain A.foo.com calling navigator.credentials.store(). Based on the blog post[1] in June announcing this feature, which said: > You must explicitly store the password using navigator.credentials.store(), so that when a user chooses a credential by tapping on the dialog, the password gets passed and copied to the current origin. ...the reproduction case below demonstrates a bug. However, AFAICT, the spec[2] allows this behavior. I'll first say that we opened this as a security bug out of an abundance of caution. We understand that the reproduction likely demonstrates intended behavior. That being said, we believe that behavior to be surprising and dangerous. Frankly, it really seems like this breaks the web. Specifically, in our opinion, the user indicating that they want to save credentials on a subdomain should *not* be a signal to their user agent that any other subdomain can ask them for those credentials in plaintext (or any other form) without the original subdomain's explicit consent. 1: https://developers.google.com/web/updates/2017/06/credential-management-updates#credentials_can_be_shared_from_a_different_subdomain 2: https://w3c.github.io/webappsec-credential-management/#security-credential-access 3: https://developers.google.com/web/updates/2017/03/nic57 VERSION Chrome Version: 57+ stable Operating System: All (Tested on MacOS only) REPRODUCTION CASE 1) Navigate to https://admin-dot-example.glitch.me/ 2) Enter a username and password and click 'Log in' 3) Click 'Save' to indicate you want Google Smart Lock to save your password for this site 4) Click 'Click here to repro' link 5) Click 'Sign In' to indicate you want to sign in with your account saved with Google Smart Lock 6) Observe that your username and password are displayed
,
Aug 18 2017
I should note that we are aware that Chrome has implemented password autofill across subdomains for some time. So, for example, these steps result in the same disclosure of credentials: 1) Navigate to https://admin-dot-example.glitch.me/ 2) Enter a username and password and click 'Log in' 3) Click 'Save' to indicate you want Google Smart Lock to save your password for this site 4) Navigate to https://www2-dot-example.glitch.me/ 5) Click in the Username form field and select the username you entered in step 2 6) Observe that your username and password are displayed However, in this case, attackers have to construct a login form that appears legitimate to the user. In many cases, the attacker's login form must be customized for each target subdomain. The Smart Lock dialog, however, appears the same regardless of which subdomain asks the browser to display it. We feel this makes the attacker's job substantially easier. For example, a malicious ad could try to sniff credentials whenever it is displayed outside an iframe. We're happy to file this issue with the spec instead, if y'all decide that it's working as expected. Thanks!
,
Aug 23 2017
We have identified a potential workaround that *may* satisfy our needs: we can use Object.defineProperty to clobber navigator.credentials on pages where we don't want navigator.credentials.get to be called:
```
Object.defineProperty(navigator, 'credentials', {
configurable: false,
enumberable: true,
value: {
get: () => Promise.reject('Credentials API disabled')
},
writable: false
});
```
The below steps demonstrate that the original reproduction steps no longer disclose credentials:
1) Navigate to https://admin-dot-example.glitch.me/
2) Enter a username and password and click 'Log in'
3) Click 'Save' to indicate you want Google Smart Lock to save your password for this site
4) Navigate to https://www3-dot-example.glitch.me/
5) Observe that 'Exploit failed: Credentials API disabled' is displayed
This sort of thing always makes me nervous - there can be many ways to reach and use a particular value in JS. Thus far, I've not found any way to use the original values in question that doesn't throw an 'Illegal invocation' or a DOMException. I suspect I've not tried everything.
Note that this workaround may not work in browsers with different ideas about how Object.defineProperty interacts with host objects.
,
Aug 25 2017
vasilii@, would you be the right person to resolve this?
,
Aug 26 2017
,
Aug 26 2017
,
Aug 28 2017
That was a conscious decision. A credential for a subdomain is offered in the account chooser. It always requires a user click before it's returned. You may see the (i) icon next in the dialog which displays the origin on hover. Without the feature UX suffers a lot. Imagine a credential saved for facebook.com and later used on m.facebook.com. If you want to suppress it then the right way would be to add your site to the public suffix list (https://publicsuffix.org/). Note, that without that step the two sites share cookies with each other. It's not secure too.
,
Aug 28 2017
Ok. I'll file a bug with the spec. Thanks for taking a look.
,
Aug 28 2017
Filed https://github.com/w3c/webappsec-credential-management/issues/102. Thanks again, y'all.
,
Dec 4 2017
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot |
|||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||
Comment 1 by elawrence@chromium.org
, Aug 18 2017Status: Untriaged (was: Unconfirmed)