Skip to content
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

Clarify 127.0.0.1 in spec #1204

Closed
gmandyam opened this issue Apr 24, 2019 · 20 comments
Closed

Clarify 127.0.0.1 in spec #1204

gmandyam opened this issue Apr 24, 2019 · 20 comments

Comments

@gmandyam
Copy link

Webauthn is only exposed in secure contexts. However current secure context definition has a carveout for 127.0.0.1 due to localhost resolution issues - see https://www.w3.org/TR/secure-contexts/#localhost. However the Secure Contexts spec says that this carveout is "at risk".

Rather than rely on a potentially shifting definition of secure context, recommendation is to specifically state in the Webauthn specification that 127.0.0.1 is an acceptable domain but localhost is not. This can be done by adding additional text to the note in https://w3c.github.io/webauthn/#rp-id. Maybe something like:

"A relying party's webpage may be locally hosted (i.e. instantiated on the same device as the user agent). In this case, the RP ID is 127.0.0.1."

@equalsJeffH
Copy link
Contributor

We discussed this on the 1-May-2019 webauthn call. We noted that this would not be a simple change since the RP ID is defined in terms of valid domain string, effective domain, and being a registrable domain suffix of the origin's effective domain (the latter alg specifically excludes hostnames that are an IPv4 address or an IPv6 address). Additionally there are various issues with using identifiers other than fully qualified DNS domain names in TLS server certificates.

The consensus on the call was to not address this Issue and close it with no action.

@gmandyam
Copy link
Author

gmandyam commented May 2, 2019

@equalsJeffH

I would like to make a counter-proposal then: all domain names that resolve to 127.0.0.1 should have the same RP ID. I am indifferent as to what the RP ID actually is (e.g. "localhost.example.com" in the Let's Encrypt article https://letsencrypt.org/docs/certificates-for-localhost/), but it could be "localhost" as a starting point.

@equalsJeffH equalsJeffH added this to the L2-WD-02 milestone May 3, 2019
@equalsJeffH
Copy link
Contributor

@gmandyam

I would like to make a counter-proposal then: all domain names that resolve to 127.0.0.1 should have the same RP ID. ... (e.g. "localhost.example.com" in the Let's Encrypt article https://letsencrypt.org/docs/certificates-for-localhost/)

intriguing idea, thx -- I think we shud investigate this. let's keep this open and targeted for a later milestone.

@agl
Copy link
Contributor

agl commented May 3, 2019

all domain names that resolve to 127.0.0.1 should have the same RP ID

That would mean that processing Webauthn requests depends on doing DNS resolution. And the DNS resolution at what time? At the time of the request? What if a network attacker changes the result after page load? At the time of loading? But loading doesn't have to involve DNS at all. I fear that is unworkable.

@gmandyam
Copy link
Author

gmandyam commented May 3, 2019

all domain names that resolve to 127.0.0.1 should have the same RP ID

That would mean that processing Webauthn requests depends on doing DNS resolution. And the DNS resolution at what time? At the time of the request? What if a network attacker changes the result after page load? At the time of loading? But loading doesn't have to involve DNS at all. I fear that is unworkable.

When I used the term "resolve", I did not mean DNS resolution. In fact, I hope that browser vendors don't try to resolve localhost via DNS and are able to leverage platform handling of loopback addresses (e.g. hosts files). If they have to resolve via DNS, I hope the requests get handled as per the guidance in https://tools.ietf.org/html/draft-ietf-dnsop-let-localhost-be-localhost-02.

@agl - does Chrome try to resolve localhost using DNS? What RP ID does Chrome currently assign to webpages hosted at 127.0.0.1?

@agl
Copy link
Contributor

agl commented May 3, 2019

does Chrome try to resolve localhost using DNS?

I believe that localhost will be resolved the same as any other name, although I'm not completely sure about that. But certainly if the rule is “all domain names that resolve to 127.0.0.1” then DNS would be involved. If “resolve” doesn't mean normal name resolution, then what did you have in mind?

What RP ID does Chrome currently assign to webpages hosted at 127.0.0.1?

Origins on 127.0.0.1 cannot use Webauthn in Chrome. (The origin https://localhost can, however.)

@gmandyam
Copy link
Author

gmandyam commented May 3, 2019

I believe that localhost will be resolved the same as any other name, although I'm not completely sure about that. But certainly if the rule is “all domain names that resolve to 127.0.0.1” then DNS would be involved.

Modifying the hosts file is supposed to override DNS.

Origins on 127.0.0.1 cannot use Webauthn in Chrome. (The origin https://localhost can, however.)

OK. I'm going to take that to mean that http://127.0.01:8080 is not allowed to access Webauthn. What is the RPID for https://localhost?

@ve7jtb
Copy link
Contributor

ve7jtb commented May 3, 2019

http://localhost shoulden't be allowed as a RPID because the https: scheme is required unless I am missing something significant.

Is https://localhost even possible?

@gmandyam
Copy link
Author

gmandyam commented May 3, 2019

@agl

More info on Windows host name resolution: https://support.microsoft.com/en-us/help/172218/microsoft-tcp-ip-host-name-resolution-order. Don't know if it current.

If you want to know of another alternative to DNS lookup, I have worked on several mobile solutions where the SRV records were on the local file system (due to unreliability of DNS servers for certain services when the phone was roaming).

@agl
Copy link
Contributor

agl commented May 3, 2019

http://localhost shoulden't be allowed as a RPID because the https: scheme is required unless I am missing something significant.

A secure origin is required. HTTPS is one option for that, but there are others.

Is https://localhost even possible?

Yes. Either add an exception for an invalid certificate or create a local CA and issue a certificate for localhost.

What is the RPID for https://localhost?

localhost

Modifying the hosts file is supposed to override DNS.

That's true, but I must be misunderstanding you. The original wording was “all domain names that resolve to 127.0.0.1” but I can edit a file here and make foo.google.com resolve to 127.0.0.1, but I can't see that it helps anything if that causes the RP ID for https://foo.google.com to be localhost.

@gmandyam
Copy link
Author

gmandyam commented May 6, 2019

That's true, but I must be misunderstanding you. The original wording was “all domain names that resolve to 127.0.0.1” but I can edit a file here and make foo.google.com resolve to 127.0.0.1, but I can't see that it helps anything if that causes the RP ID for https://foo.google.com to be localhost.

Let's go with this example. Assume that there is a web page hosted at 127.0.0.1 and it serves up a self-signed cert with foo.google.com. I assume the effective domain will be google.com, and even though some browsers may reject such a connection - there is nothing in the Webauthn spec or even the SecureContext spec that specifically disallows use of the Webauthn API from a caller in such a webpage.

Now assume that the authenticator is CTAP-enabled and has already created a credential for google.com based on a previous session with a Google server presenting a valid cert. if the client passes for instance a getAssertion command (https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#authenticatorGetAssertion), it seems that the rpid argument for this example will be google.com (even though the webpage was served up from the loopback address) and there is nothing in the CTAP spec as far as I can tell would prevent the authenticator from using the google.com credential to create an assertion for this foo.google.com webpage. If the rpid was instead localhost fthen the google.com credential won't be available for use by the webpage in this example.

If the above is actually not possible, please point me to the exact parts of the Webauthn specification that prevent this situation from occuring.

@emlun
Copy link
Member

emlun commented May 7, 2019

Assume that there is a web page hosted at 127.0.0.1 and it serves up a self-signed cert with foo.google.com. I assume the effective domain will be google.com, [...]

Now assume that the authenticator [...] has already created a credential for google.com [...] the rpid argument for this example will be google.com (even though the webpage was served up from the loopback address) [...]

Allowing the effective domain to be faked like that sounds very dangerous to me. Less so if it only applies to 127.0.0.1 as a special case, but I imagine it still wouldn't be terribly difficult to turn that into a practical attack bypassing WebAuthn's phishing protection.

@agl
Copy link
Contributor

agl commented May 10, 2019

Let's go with this example. Assume that there is a web page hosted at 127.0.0.1 and it serves up a self-signed cert with foo.google.com.

Ok:

  • DNS for foo.google.com resolves to 127.0.0.1
  • Server on 127.0.0.1:443 serves self-signed certificate for foo.google.com
  • User enters https://foo.google.com, browser loads from local server.
  • User presumably overrides the certificate error.

Then yes, that Javascript can exercise the RP ID google.com.

But your proposal was:

All domain names that resolve to 127.0.0.1 should have the same RP ID

But here, foo.google.com is a domain name that resolves to 127.0.0.1, but it doesn't have the same RP ID as all others domains that resolve to 127.0.0.1.

@gmandyam
Copy link
Author

Ok:

DNS for foo.google.com resolves to 127.0.0.1
Server on 127.0.0.1:443 serves self-signed certificate for foo.google.com
User enters https://foo.google.com, browser loads from local server.
User presumably overrides the certificate error.

I thought the example that you proposed was that the hosts file would be modified ("I can edit a file here and make foo.google.com resolve to 127.0.0.1"). Which file were you editing? How did DNS enter the picture? I may have misunderstood your original example.

@equalsJeffH
Copy link
Contributor

fyi:

Ok:

DNS for foo.google.com resolves to 127.0.0.1
Server on 127.0.0.1:443 serves self-signed certificate for foo.google.com
User enters https://foo.google.com, browser loads from local server.

I got this to "work" on debian for https://localhost in chrome, once I enabled chrome://flags/#allow-insecure-localhost. I used the "Making and trusting your own certificates" instructions here https://letsencrypt.org/docs/certificates-for-localhost/.

User presumably overrides the certificate error.

In chrome, there seems to be no recourse for overriding the cert error. The only way I got it to work was enabling the allow-insecure-localhost flag and restarting chrome.

WRT:

I would like to make a counter-proposal then: all domain names that resolve to 127.0.0.1 should have the same RP ID.

To which I'd offhandedly (and sorta embarrassingly, given the security implications) replied: intriguing idea, thx -- I think we shud investigate this:

It seems to me we've now investigated/discussed this and there's not anything to add to the webauthn spec in regards to it. Presumably, on my machine here, I ought to be able to now run a webauthn-wielding webapp on localhost for testing or whatever purposes (tho it does require jumping thru various hoops, and I haven't tested the running a webauthn-wielding webapp as yet). Presumably, I could add further hostnames to /etc/hosts that resolve to 127.0.0.1 and create self-signed certs (or one cert with multiple dnsname subjectAlternativeName entries) for them and (I'm guessing) that'd work.

@gmandyam
Copy link
Author

Presumably, on my machine here, I ought to be able to now run a webauthn-wielding webapp on localhost for testing or whatever purposes (tho it does require jumping thru various hoops, and I haven't tested the running a webauthn-wielding webapp as yet). Presumably, I could add further hostnames to /etc/hosts that resolve to 127.0.0.1 and create self-signed certs (or one cert with multiple dnsname subjectAlternativeName entries) for them and (I'm guessing) that'd work.

Yes, but will the Webauthn caller be assigned an RP ID = localhost for all of the domain names that resolve to 127.0.0.1?

Note that the CTAP spec normatively refers to Webauthn's definiton of RP ID: https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#authenticatorMakeCredential.

Note also that long-standing FIDO Privacy Principles (https://fidoalliance.org/whitepaper-on-privacy-principles/) state: "Other technical safeguards within the FIDO specifications include that a key issued to a particular website can only be exercised in a web browser by that website, amplifying the strong boundary between different sites. This requirement renders useless the theft of a public key for the purposes of phishing from another origin, and also prevents multiple colluding sites from using an Authenticator to strongly verify and correlate a user’s identity as he or she browses the Web."

So it seems that the current CTAP normative reference to the Webauthn definition of RP ID is problematic if there is a way for a webpage hosted at the loopback address to be able to use an RP ID corresponding to a domain that is not associated with that address. There are certainly legitimate reasons to set up test pages on the loopback address, but such pages (if they are going to be allowed to invoke Webauthn) should not result in privacy (linkability) violations through the CTAP protocol.

One solution is could be to augment the RP ID definition in the CTAP spec and create appropriate requirements for RP ID in any client beyond what Webauthn calls for. If so, then you are right - there's not anything to add to the Webauthn spec. It is the CTAP spec where this needs to be addressed.

@emlun
Copy link
Member

emlun commented May 17, 2019

@gmandyam I'm not sure what problem you're trying to solve. Is it that locally hosted applications can successfully create assertions for arbitrary RP IDs if the user permits a self-signed server certificate?

Because in that case I don't see why loopback addresses should be special. If I can edit a victim's hosts file to add google.com = 127.0.0.1 and host a self-signed application on the victim's machine, then I can just as well add google.com = 174.28.13.83 and host the same self-signed application at that IP address. The latter is in fact an easier attack since I need to do less on the victim's machine.

@gmandyam
Copy link
Author

gmandyam commented May 17, 2019

@emlun

Sorry - let me try and get back to what I believe is the issue with the spec. The spec is ambiguous as to the use of localhost as a valid origin for a secure context. The reason it is ambiguous is that the Secure Context spec itself is ambiguous - see https://www.w3.org/TR/secure-contexts/#localhost.

The algm. provided in the Secure Context's spec makes a special allowance for 127.0.0.1 - see https://www.w3.org/TR/secure-contexts/#is-origin-trustworthy. However it is silent as to whether localhost can be even "potentially trustworthy." So I filed an issue so that the spec can clarify this. I don't believe it is constructive to file an issue without suggesting a potential resolution, so I did. In hindsight, that was a mistake because we have now gone down several side explorations on DNS resolution, browser permissions, host files and self-signed certs. This was all informative, but outside the scope of the spec.

The Chrome browser currently allows https://localhost but does not allow https://127.0.0.1 to access the Webauthn API (if I understood @agl correctly - sorry, I only do testing on FF so I have not confirmed myself). To me, this does not seem to be consistent with the Secure Context algorithm(s) for determining if a domain is trustworthy or potentially-trustworthy. If this is the expected browser behavior, then it should be called out in the spec - e.g. in the note in https://www.w3.org/TR/webauthn/#rp-id.

Regarding any potential risks with RP ID that could occur modifying the hosts file, DNS entries, etc. - this could be documented as well - maybe in the Security Considerations section under a new section on domain authentication. However, that is not what was intended when filing this issue. That would be something to consider in a separate issue/PR.

@gmandyam
Copy link
Author

Just to let you know, I did confirm that Chrome does not consider 127.0.0.1 (or to be more precise 127.0.0.1:80) to be a secure context, but will accept the same page from localhost as a secure context and will allow a Webauthn caller. FF accepts 127.0.0.1:80.

I really fail to understand why this would be considered a positive, if two different implementors have a different interpretation of what constitutes a secure context. Which one is is implementing the spec correctly?

@equalsJeffH
Copy link
Contributor

see arguments above. closing this as this really ought to be addressed in the security-context spec (where perhaps this issue ought to be re-assigned to....)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants