Closed sbweeden closed 1 month ago
Related:
Alternatives in this field require browser redirects or iframes that access both a.com (for authentication) and then perform federated SSO to b.com. This is an undersirable user experience in many cases.
I'm curious in what cases would the iframe UX be undesirable or insufficient.
Alternatives in this field require browser redirects or iframes that access both a.com (for authentication) and then perform federated SSO to b.com. This is an undersirable user experience in many cases.
I'm curious in what cases would the iframe UX be undesirable or insufficient.
There are enterprise examples where network partitioning makes only b.com (and not a.com) accessible from browser at a particular point in time.
There are consumer examples where b.com does not want to expose redirects to a.com all the way back to the browser - b.com wants to control the UX at all times. This latter example is similar to the requirement Dirk discussed regarding payments processing at a PSP (not wanting any redirect to the customer's bank).
Putting another hole in the same-origin policy with a new facet-like mechanism isn't necessary for the consumer example; our permissions issue in #1336 aside, the iframe mechanisms are or will be sufficient to avoid redirects, even though they aren't in Level 1.
The enterprise example is rather unconvincing; I've certainly worked in such environments before, but I don't see why WebAuthn should have to adopt significant security and protocol complexity to facilitate a legacy authentication design.
The goals of WebAuthn never included needing to tie cleanly into multi-domain LDAP/AD sync systems, and shouldn't: It's plenty complex as it is.
Putting another hole in the same-origin policy with a new facet-like mechanism isn't necessary for the consumer example; our permissions issue in #1336 aside, the iframe mechanisms are or will be sufficient to avoid redirects, even though they aren't in Level 1.
If that's the case, why would the payments people Dirk spoke of insist on a requirement that at runtime only connections direct to the PSP be permitted, and not to the bank?
It is quite a lot more work for an RP to deploy the iFrame + Federation, and there are different implications for network connections and traffic.
On 2020-02-19 webauthn call:
@sbweeden issues with cross-origin iframes:
wrt 3d party credentials approach:
@nadalin
@agl requests that we need detailed info on why cross-origin iframes are insufficient or onerous in web context @christiaanbrand requests input from the (web) payments folk here also
@jcjones notes that if we add yet another so-called same-origin-policy violation/relaxation we're further stirring the architecture pot....
update 2020-07-01: note also wrt the above discussion on 19-Feb, that there was also discussion of this topic during the 26-Feb-2020 webauthn F2F meeting, see: https://www.w3.org/2020/02/26-webauthn-minutes.html and search for "1372"
I'm starting to think that the runtime connection only to the PISP and not the bank argument for justifying the approach described in this issue is flawed. If a browser were to have a discovery mechanism to determine if PISP was allowed to call navigator.credentials.get using the RPID of the bank, then almost certainly that discovery mechanism needs to be hosted at some well-known URL owned by the bank (i.e. a page that's part of the site identified by the RPID). That is what is done for Android and assetlinks.json today as well. The retrieval of the discovery document becomes part of the runtime flow and whilst potentially read-only and cacheable does that really make it more highly available than assuming the browser can contact the bank for real-time loading of a cross-origin iframe?
I also have some concerns over the idea proposed by Dirk that the bank doesn't get to generate any part of the challenge, yet is responsible for verifying the assertion. This means building unsolicited assertion semantics into the protocol for freshness and nonce protection. Whilst that may eventually be a good thing and offer similar features to the time-tested unsolicited SAML-browser-POST SSO semantics, is this something that WebAuthn wants to define?
Here’s a use case we stumbled upon just yesterday:
Microsoft recently announced support for FIDO authentication in Azure Active Directory hybrid environments [1]
When a user registers a FIDO credential with Microsoft Azure, their FIDO credential is made available as an attribute (msDS-KeyCredentialLink) on the user’s Active Directory account.
For the FIDO case, this attribute contains the authdata (with credential ID) and an x509 representation of the FIDO public key. [2]
Since our product already integrates with Active Directory, we have read access to this “msDS-KeyCredentialLink”, thus we have the credentialId needed to issue a get_credential, and we have the public key we need to validate the assertion.
The only thing stopping us from reusing the user’s Azure FIDO credentials is a missing cross-origin mechanism exactly as discussed in this issue.
For an RP implementor like us, it’s seems really appealing to allow the user to reuse already registered Azure credentials instead of having to re-register the same authenticator in each and every application supporting FIDO across their enterprise. (Our product is an extension which alone can be installed in five different host products)
I understand that this could be solvable using iframe with some form of sso or federation. But that would mean special-casing the user interface for dealing with iframes and whatever is shown in the iframe would be out of our control as an RP implementor.
I sympathise with anyone worried about added complexity to the architecture. However, my sympathy is always greater with the end user. She wants it to “just work”, and I think a solution as discussed in this thread would be a great help in that regard.
One additional input: Any cross-origin solution here should be tenant-aware. In concrete terms, an Azure global administrator should be able to register relying parties for cross-origin in their tenant, without involving Microsoft. (The alternative being that Azure had one global list of allowed relying parties, which would not scale and be a security and organisational nightmare..)
That’s my 2 cents, happy to clarify this use case if anyone’s curious.
Cheers, Eirik.
[1] https://techcommunity.microsoft.com/t5/azure-active-directory-identity/public-preview-of-azure-ad-support-for-fido2-security-keys-in/ba-p/1187929 [2] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/d5948ab9-8993-4066-a175-851af361ea7f
thoughts wrt how to effect setting a cross-domain RP ID (RP ID is only a hostname at this time, not an origin (ie (scheme, host, port))) if we were to allow the latter:
Entirely relax RP ID definition and allow an RP to assert an arbitrary RP ID (valid domain string or arbitrary string) via in-page JS calling nav.creds.create()
?
Or, only allow asserting an arbitrary RP ID (valid domain string or not) via a (newly defined) WebAuthn extension.
Note: A concern with this is the potential for tracking and abuse: e.g., by RP's client-side JS creating and exercising discoverable credentials and then sharing the RP ID of the credential with other entities (eg for tracking purposes). A suggested mitigation is that any cred created with a RP ID not conformant with the creating RP's domain name MUST be a non-discoverable credential.
This seems to me like something the "credential owner" RP should have to actively opt in to, but I'm not sure how. Feature policy isn't really applicable. Maybe you could do something like a CORS preflight request and check for a response header?
A suggested mitigation is that any cred created with a RP ID not conformant with the creating RP's domain name MUST be a non-discoverable credential.
I don't think you could build a sensible user experience from that. We don't expect users to know about the discoverability of their credentials, so it would be mighty confusing why some of their credentials work and some just don't.
Hi @equalsJeffH and @emlun, as an RP developer, had some question regarding the interpretation of the spec: Section 7.1.5:
Verify that the value of C.origin matches the Relying Party's origin.
Section 7.1.9:
Verify that the value of C.origin matches the Relying Party's origin.
There's a use case where a user performs the WebAuthn registration or verification at sub.domain.com
, some portal page, then there are some redirects until the resultant WebAuthn data hits auth.domain.com
. This is where the actual RP verification happens, and at this point, the origin validation would fail, because the RP expects an origin of auth.domain.com from the request context, whereas the actual WebAuthn request was performed at sub.domain.com
.
My question is this: does the spec indicate that the RP's origin at the auth.domain.com
is required to be the sole "true" origin, or can one interpret "matches the Relying Party's origin" as allowing for some admin configuration of acceptable RP origins against which to match?
In other words, can the RP specifically configure sub.domain.com
, a.domain.com
, b.domain.com
, etc to be matches for "its" origin, and thereby accept challenges against these origins, despite the final endpoint being auth.domain.com
? It doesn't appear to be the "optimal" implementation, but given that there's some customer framework set up this way, I was wondering whether this implementation falls within acceptable bounds per the WebAuthn spec requirements.
My original reading of the spec led me to believe that there's a 1:1 correspondence between RP and origin, but it seems possible that this is outside of the requirements scope of the spec, and the implementation of the "matching" is left to the RP. Thank you so much for your time!
@mpeng-okta I assume you know that the RP ID in this sort of scenario would need to be "domain.com" if you want sub, auth, a, b, and so on to have visibility with the same set of credentials.
Speaking with a level of confidence which is quite risky in this particular forum, multiple relying parties can share RPID values. The services at sub, auth, a, and b in this example are all relying parties with different origins.
The verification here is that the value of C.origin must match the origin of your relying party. so a credential request from sub.domain.com must verify the origin in CCD as https://sub.domain.com
If auth.domain.com is an API service for handling webauthn which authenticates back-channel communication from sub.domain.com, auth can handle the validation that 'sub' is correct.
If communication between sub.domain.com and auth.domain.com happens solely via redirection, then this is much more difficult to do securely. You also could lose potential future security properties, such as stronger phishing resistance through token binding or some other channel binding. However I believe this communication between sub and auth would still be a relying party outsourcing its responsibilities, which is out of scope currently.
@mpeng-okta It will depend on the implementation details. It is certainly possible for auth.domain.com
to verify authentication assertions generated for sub.domain.com
, and accept sub.domain.com
as a "matching" domain, but one needs to take care to do that securely.
For example, in the case you describe it would presumably be sub.d(omain).c(om)
that generated the challenge
parameter. auth.d(omain).c(om)
needs to know the expected challenge in order to verify it; if auth.d.c
receives the challenge along with the assertion from the client in the redirection, then this opens up for attacks where an attacker could replay a previously captured challenge and assertion. In order to preserve the anti-replay feature, auth.d.c
would have to receive that challenge from sub.d.c
via some other, trusted channel, which might defeat some of the advantages of the redirection flow.
However, I suspect you might be better off having sub.d.c
perform the whole authentication ceremony and verify the assertion, and then return some authorization ticket (for example, an OAuth2 PKCE authorization code) instead of returning the raw WebAuthn assertion. (And it would probably be sub.d.c
that redirects to auth.d.c
, which performs the WebAuthn ceremony and then redirects back to sub.d.c
with the authorization ticket.)
Thanks so much for your replies! I see what you mean, and from my reading of the WebAuthn spec it does appear as if the most correct/secure/logical implementation would be to have sub.d.c
(or the origin whose page is actually calling the WebAuthn browser API) be the endpoint at which the entire authentication ceremony is performed. However, as mentioned it also does seem conceivable to have auth.d.c
handle the validation that sub.d.c
is acceptable as an origin (but not ideal).
In this scenario, all of the auth is being performed on the backend via the endpoint exposed at the auth.d.c
domain (including the generation of the challenge
nonce parameter). Only the WebAuthn registration/verification via browser API is happening at sub.d.c
. In other words, sub.d.c
is being passed the known challenge
and WebAuthn-related config params from auth.d.c
via a trusted channel, and sub.d.c
does is perform the navigation.credentials.create()
and navigation.credentials.get()
calls, whereupon the output data is being passed back to auth.d.c
via a trusted channel.
This use case is basically where developer users have an existing framework hosting a sign-on page at some set of sub1.d.c
, sub2.d.c
, etc domains, so the approach idea is to receive all the WebAuthn config values (e.g. user verification, authenticator attachment, allowed credentials, and so on) and challenge values from a central auth.d.c
domain, then pass the resulting outputs of the WebAuthn ceremony to a common auth.d.c
domain for the actual ultimate auth.
@emlun with respect to your last comment, I think I might be confused and would appreciate if you could fix any misunderstanding I have:
...might be better off having
sub.d.c
perform the whole authentication ceremony and verify the assertion, and then return some authorization ticket ... And it would probably besub.d.c
that redirects toauth.d.c
, which performs the WebAuthn ceremony and then redirects back to sub.d.c with the authorization ticket.)
Per the earlier mention, it sounded to me that by the last sentence you would mean:
And it would probably be ~sub.d.c~
auth.d.c
that redirects to ~auth.d.c~sub.d.c
, which performs the WebAuthn ceremony and then redirects back to ~sub.d.c~auth.d.c
with the authorization ticket.)
Is that accurate? Just wanted to check my understanding in case I missed anything. (unfortunately the use case and approach as described don't follow your guideline immediately above, as it's a particular customer case that leverages the RP as the WebAuthn auth provider here, so my description of the approach is just the best effort to fill the ask while fitting the spec)
This use case is basically where developer users have an existing framework hosting a sign-on page at some set of
sub1.d.c
,sub2.d.c
, etc domains, so the approach idea is to receive all the WebAuthn config values (e.g. user verification, authenticator attachment, allowed credentials, and so on) and challenge values from a centralauth.d.c
domain, then pass the resulting outputs of the WebAuthn ceremony to a commonauth.d.c
domain for the actual ultimate auth.
Note that in this use case, you will probably have to set the RP ID to just domain.com
, without the more specific subdomain. Otherwise, sub1.domain.com
and sub2.domain.com
will not be able to exercise each others' credentials, so the user would have to register once per subdomain (and auth.d.c
would need access to the user's credential public keys from each sibling domain). Whereas with rpId: "domain.com"
, all three subdomains could exercise the same credential which the user needs to register only once.
@emlun with respect to your last comment [...]
No, I just meant that the example names seemed a bit backward. It seems more likely that auth.d.c
would be the one performing the authentication instead of consuming the authentication result. You can just ignore the final parenthetical in my previous comment, it doesn't really add anything new.
Yeah, that's a great point w.r.t. the RP ID scoping. In this particular case, I believe the customer tenants might have region-specific portals e.g. us-west.domain.com, us-east.domain.com (which they would want to scope). However, from an RP perspective, it would also be useful to implement more configurable RP ID matching in some cases as you mentioned, so that those customers that would want interoperability among domains would get their use case satisfied as well.
And ah got it, yeah it'd make more sense for the endpoint's page where the WebAuthn browser API is called to do the entire auth, then pass on an authorization token when done (hence it'd make more sense for the initial page to be auth.d.c
, which performs all the validation then passes the token to sub.d.c
).
In this case, the customer setup is such that the initial sub.d.c
page has no access to the RP validations, and the final auth.d.c
endpoint is the API-only RP auth endpoint which performs all the verification. So the developer customer ends up having the auth.d.c
domain do all the actual RP validations and returning the relevant API response to the initial portal page of sub.d.c
via a secure channel, and having the WebAuthn browser UI interactions on sub.d.c
.
Thanks so much for the clarifications and helpful discussion! Really appreciate it.
@mpeng-okta In the case of having region-specific portals, would each region also have its own IdP (which would likely be the FIDO RP)?
on 2021-01-06 call: this scenario is not addressed ( says @sbweeden ) by the "3P Credential" proposal. This is "essentially facets". The use case is would nominally be addressed by something like Digital Asset Links. i.e., the webauthn spec perhaps ought to stipulate something along these lines, eg, if there's use case(s) not addressed by eg webauthn in cross-origin iframes.
Using WebAuthn within WebExtension is also a challenge with the current restrictions. In fact, browsers are using different "domains" or "app ids" for a same service and this impact the interoperability between browsers.
Using WebAuthn within WebExtension is also a challenge with the current restrictions
If one does WebAuthn operations within a site's origin then it'll be scoped to that origin for the purposes of RP ID selection. But that's true of all operations that an extension injects into a page.
If an extension wishes to perform WebAuthn “itself”, i.e. operating as an RP, then that's not officially supported. It will work in Chrome if you don't specify an RP ID (Chrome will use the “chrome-extension://” address as the RP ID) but this is non-standard.
I was indeed talking about operating an extension as a RP.
If an extension wishes to perform WebAuthn “itself”, i.e. operating as an RP, then that's not officially supported. It will work in Chrome if you don't specify an RP ID (Chrome will use the “chrome-extension://” address as the RP ID) but this is non-standard.
Indeed it will work if you don't specify the RPID or if you use the exact extension ID (same thing for Firefox browser (until Mozilla fix a bug that makes the flow hanging)). It might be non-standard as of today but it's also the only way to leverage FIDO2 in this context. This also causes interoperability issues with other implementations of FIDO2 on other platforms like Android / iOS.
I'm interested to understand how this discussion can lead to changes in the spec (who has authority on it) and how we can all collaborate to extend the support of WebAuthn.
I'm interested to understand how this discussion can lead to changes in the spec (who has authority on it) and how we can all collaborate to extend the support of WebAuthn.
This is the group that does spec changes, so you're in the right place.
I'm guessing from your wording “interoperability issues with other implementations of FIDO2 on other platforms like Android / iOS” that you're considering the extension to be an app, rather than the classic use of an extension to tweak other sites. Thus you want the app to have a consistent RP identity across platforms so that users can sign into it across them?
If that's the case then I think an extension is not quite the right model. If you want a consistent RP identity then (absent large changes) that's a domain. If you use a PWA rather than an extension then you can still work offline etc, but you can register and assert credentials using a domain name. On Android, a native app can use Android's WebAuthn APIs with that domain as the RP ID if it sets up asset links (docs). iOS doesn't currently offer a WebAuthn API to native apps that I'm aware of.
Why couldn't WebAuthn be used for 2FA/Passwordless/Usernameless logins for browser extensions that want to offer an additional level of access control? It's not much different than how some privacy-oriented apps offer a secondary passcode you have to enter when you open the app.
I think we should consider updating the spec to enable alternative RP implementations outside of the traditional "remote server" definition of what an RP is. Use cases for the technology can come out of nowhere, as in the case of an extension developer who wants to leverage an "internal RP" that is completely contained with the extension to allow for attestations and assertions for local authentication.
If that's the case then I think an extension is not quite the right model.
@agl Here you put the authentication as the core of the product, which is not often the case. If you want a real use case example, I work for a password manager, so it's both an app (to manage your secrets) and a content-script (to autofill web-forms).
In this specific case providing passwordless authentication with the fingerprint or 2FA using roaming auth is an important feature in term of convenience on one side and security on the other. We are currently using U2F and interoperability is working just fine between Windows/Mac/Android/iOS. Now the web extensions are missing here, and the next logical step is to migrate to WebAuthn (and FIDO2 more broadly).
So two things at the moment:
Few resources that could help:
@Mikescops with the example of an application, lets call it AsteriskAsterisk. There is a desire to authenticate access with WebAuthn. The existing model would be.
I assume the password manager use case is to use platform and roaming authenticators to gate access to the password vault - do you see a reason this model would not work with such an application?
A custom URL scheme of browser extensions will mostly not be standardized to be consistent - among other things, this would require them to all identify the author of the extension in the same manner. Without standardization, any custom url scheme is internal and subject to differ by tons of different factors - browser, browser release stream, extension via store vs direct download vs development, even the filesystem path of the local sandboxing container. This variance would break the ability to use the existing credential created by whichever RPID it was originally created against - you have a roaming authenticator, but it will not necessarily work when you actually roamed to a machine with a different os/browser/extension combo.
@dwaite this makes sense and this how U2F is currently working, you set your appID / RPID to be your domain.com
then a roaming authenticator is usable accross platforms.
For anyone jumping in the conversation, the part of the spec we are talking about is: https://w3c.github.io/webauthn/#rp-id
By default, the RP ID for a WebAuthn operation is set to the caller’s origin's effective domain. This default MAY be overridden by the caller, as long as the caller-specified RP ID value is a registrable domain suffix of or is equal to the caller’s origin's effective domain.
Other specifications mimicking the WebAuthn API to enable WebAuthn public key credentials on non-Web platforms (e.g. native mobile applications), MAY define different rules for binding a caller to a Relying Party Identifier. Though, the RP ID syntaxes MUST conform to either valid domain strings or URIs.
So the implementation of browser extensions should be adapted to be able to use the owner's domain (how the verification could be done is an unknown).
But then this differs from the initial topic of this issue which was about allowing cross-domain use between a.c
and b.c
. Shall we create a different thread?
@MasterKale
Why couldn't WebAuthn be used for 2FA/Passwordless/Usernameless logins for browser extensions that want to offer an additional level of access control? It's not much different than how some privacy-oriented apps offer a secondary passcode you have to enter when you open the app.
I think we should consider updating the spec to enable alternative RP implementations outside of the traditional "remote server" definition of what an RP is. Use cases for the technology can come out of nowhere, as in the case of an extension developer who wants to leverage an "internal RP" that is completely contained with the extension to allow for attestations and assertions for local authentication.
WebAuthn couldn't be used for local authentication like this because it is a challenge-response authentication method, and challenge-response authentication only works when client and server are separate. Otherwise the user can bypass the authentication by simply using a different client without the authentication check. Local access control requires encryption, which WebAuthn is currently not equipped for. This could change in the future with the proposed prf
extension, but that's not currently in the spec.
Granted, it is possible for the "server" part to be a local application running in a secure enclave along with and trusted by the operating system, but as far as I know userspace applications are rarely deployed like that.
By contrast, @Mikescops's use case of a browser extension authenticating itself to a remote server (for example, to download an encrypted vault file) is a different matter and is compatible with challenge-response authentication.
@emlun that's correct. Local access control would need a secure local storage too if I'm not misunderstanding the extension?
Encryption would be used to implement a secure local storage (and thus control access to its contents), so I suppose yes, in a way.
By contrast, @Mikescops's use case of a browser extension authenticating itself to a remote server (for example, to download an encrypted vault file) is a different matter and is compatible with challenge-response authentication.
It appears I misunderstood @Mikescops's use case - I inferred that the RP was running locally too. Understanding now that their RP is indeed remote, I still see the issue they're having to deal with because RP ID definition is vague about clients running in website-adjacent contexts.
WebAuthn couldn't be used for local authentication like this because it is a challenge-response authentication method, and challenge-response authentication only works when client and server are separate. Otherwise the user can bypass the authentication by simply using a different client without the authentication check.
In my defense I never said it would be a good mechanism for login if the RP was running locally 😛. I agree that WebAuthn running locally would be as effective a login mechanism as a PIN one would enter. Unless the app takes additional steps to encrypt the data locally it's at best a way to keep unmotivated attackers out of local data.
But then this differs from the initial topic of this issue which was about allowing cross-domain use between a.c and b.c. Shall we create a different thread?
@Mikescops: I don't see why not, feel free to make a new issue so this thread can remain about cross-subdomain use.
@sbweeden Can we close this
This topic came up again as a recent FIDO plenary BOF led by @timcappalli
I'd like his take on possible solutions before closing.
I agree this topic is important and shouldn't be closed without solution. I know the discussion has been stale for too much time now but I'd be happy to bring it back on the table.
@Mikescops This may be closed without a solution but will not be closed without a resolution. This issue is at risk as there has not been much progress in the last 1.5 years so its on the chopping block
Any plans to add https://github.com/w3c/webauthn/wiki/Explainer:-Related-origin-requests in the spec?
Any plans to add https://github.com/w3c/webauthn/wiki/Explainer:-Related-origin-requests in the spec?
Yes
@timcappalli is there a good way to track progress on it? I couldn't find anything by searching online, nor in the explainer.
@timcappalli is there a good way to track progress on it? I couldn't find anything by searching online, nor in the explainer.
https://chromestatus.com/feature/4635336177352704
Spec text is on my to do list.
This issue is to capture discussion / decision making related to a discussion opened on the mailing list:
https://lists.w3.org/Archives/Public/public-webauthn/2020Feb/0001.html
The summary of the request is to allow an RP to advertise an allowed list of other web origins at which a credential issued to the RPID controlled by the RP may be used.
For example consider a credential created via WebAuthn at a site login.a.com, using RPID a.com.
The authority in control of a.com would like to permit use of this credential at other web origins such as b.com and c.com, without having to have separate credentials registered at those web domains.
This is similar in principal to the facet list feature of FIDO U2F. It has application within a company that controls different web domains (perhaps brands, or mergers and acquisitions).
Alternatives in this field require browser redirects or iframes that access both a.com (for authentication) and then perform federated SSO to b.com. This is an undersirable user experience in many cases.
A proposed solution could allow a.com (via some form of web discovery including via DNS, or a hosted page) to control the list of RPIDs or web origins that are permitted to use a.com's RPID in calls to navigator.credentials.get(). The solution requires the client (in this case the browser) to understand and discover this trust relationship, something that is already done for other web access control protocols today. I don't plan to prescribe a particular method here, just ask that one be considered.
This is already done for Android native apps today to permit sharing of a credential with a WebAuthn RPID via the assetlinks.json hosted discovery document. Clearly non-browser and browser clients want to be able to do this - the same should be able to apply for cross-domain browser-based use of credentials. Preferably the trust model is sharable across different client types so that we don't end up with every client type building their own bespoke model.