-
Notifications
You must be signed in to change notification settings - Fork 209
adds Related Origin Requests #2040
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
Changes from 31 commits
0522807
d48a18c
2a18351
689647c
3aad054
5187e72
881ac8f
9062a15
2315db8
8ea0303
28a2b0f
b51bd16
a21babf
7466f32
e7d0c7c
b3bf34c
bdba742
de25c37
71e4e80
26d350c
a2ac319
b120220
bcec7fa
3ba2ff3
a108a2c
c0c40d1
ebf03eb
e4f24d9
2e9bdcf
2462fd8
9da2c4b
017a5e3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1228,6 +1228,12 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S | |
: <dfn>Non-Discoverable Credential</dfn> | ||
:: This is a [=credential=] whose [=credential ID=] must be provided in {{PublicKeyCredentialRequestOptions/allowCredentials}} when calling {{CredentialsContainer/get()|navigator.credentials.get()}} because it is not [=client-side discoverable credential|client-side discoverable=]. See also [=server-side credentials=]. | ||
|
||
: <dfn>Registrable Origin Label</dfn> | ||
:: The first [=domain label=] of the [=registrable domain=] of a [=domain=], | ||
or null if the [=registrable domain=] is null. | ||
For example, the [=registrable origin label=] of both `example.co.uk` and `www.example.de` is `example` | ||
if both `co.uk` and `de` are [=public suffixes=]. | ||
|
||
: <dfn>Public Key Credential</dfn> | ||
:: Generically, a *credential* is data one entity presents to another in order to *authenticate* the former to the latter | ||
[[RFC4949]]. The term [=public key credential=] refers to one of: a [=public key credential source=], the | ||
|
@@ -1824,11 +1830,21 @@ a numbered step. If outdented, it (today) is rendered as a bullet in the midst o | |
|
||
: is present | ||
:: If <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> [=is not a | ||
registrable domain suffix of and is not equal to=] |effectiveDomain|, throw a "{{SecurityError}}" {{DOMException}}. | ||
registrable domain suffix of and is not equal to=] |effectiveDomain|, and if the client | ||
|
||
<dl class="switch"> | ||
: supports [[#sctn-related-origins|related origin requests]] | ||
:: 1. Let |rpIdRequested| be the value of <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code>. | ||
|
||
: Is not present | ||
:: Set <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> to | ||
|effectiveDomain|. | ||
1. Run the [$related origins validation procedure$] with arguments |callerOrigin| and |rpIdRequested|. | ||
If the result is [FALSE], throw a "{{SecurityError}}" {{DOMException}}. | ||
|
||
: does not support [[#sctn-related-origins|related origin requests]] | ||
:: throw a "{{SecurityError}}" {{DOMException}}. | ||
</dl> | ||
|
||
: is not present | ||
:: Set <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> to |effectiveDomain|. | ||
</dl> | ||
|
||
Note: <code>|pkOptions|.{{PublicKeyCredentialCreationOptions/rp}}.{{PublicKeyCredentialRpEntity/id}}</code> represents the | ||
|
@@ -2314,19 +2330,31 @@ When this method is invoked, the user agent MUST execute the following algorithm | |
PKI-based security. | ||
|
||
<li id='GetAssn-DetermineRpId'> | ||
If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> is not present, then set |rpId| to | ||
|effectiveDomain|. | ||
If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> | ||
<dl class="switch"> | ||
|
||
Otherwise: | ||
: is present | ||
:: If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> [=is not a | ||
registrable domain suffix of and is not equal to=] |effectiveDomain|, and if the client | ||
|
||
1. If <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> [=is not a registrable domain suffix of and is not | ||
equal to=] |effectiveDomain|, throw a "{{SecurityError}}" {{DOMException}}. | ||
<dl class="switch"> | ||
: supports [[#sctn-related-origins|related origin requests]] | ||
:: 1. Let |rpIdRequested| be the value of <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> | ||
|
||
1. Run the [$related origins validation procedure$] with arguments |callerOrigin| and |rpIdRequested|. | ||
If the result is [FALSE], throw a "{{SecurityError}}" {{DOMException}}. | ||
|
||
1. Set |rpId| to <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code>. | ||
: does not support [[#sctn-related-origins|related origin requests]] | ||
:: throw a "{{SecurityError}}" {{DOMException}}. | ||
</dl> | ||
|
||
Note: |rpId| represents the caller's [=RP ID=]. The [=RP ID=] defaults to being the caller's [=environment | ||
settings object/origin=]'s [=effective domain=] unless the caller has explicitly set | ||
<code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> when calling {{CredentialsContainer/get()}}. | ||
: is not present | ||
:: Set <code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> to |effectiveDomain|. | ||
</dl> | ||
|
||
Note: |rpId| represents the caller's [=RP ID=]. The [=RP ID=] defaults to being the caller's [=environment | ||
settings object/origin=]'s [=effective domain=] unless the caller has explicitly set | ||
<code>|pkOptions|.{{PublicKeyCredentialRequestOptions/rpId}}</code> when calling {{CredentialsContainer/get()}}. | ||
</li> | ||
|
||
1. Let |clientExtensions| be a new [=map=] and let |authenticatorExtensions| be a new [=map=]. | ||
|
@@ -3963,6 +3991,7 @@ Note: The {{UserVerificationRequirement}} enumeration is deliberately not refere | |
"hybridTransport", | ||
"passkeyPlatformAuthenticator", | ||
"userVerifyingPlatformAuthenticator", | ||
"relatedOrigins" | ||
}; | ||
</xmp> | ||
|
||
|
@@ -3985,6 +4014,9 @@ Note: The {{ClientCapability}} enumeration is deliberately not referenced, see [ | |
|
||
: <dfn>userVerifyingPlatformAuthenticator</dfn> | ||
:: The [=WebAuthn Client=] supports usage of a [=user-verifying platform authenticator=]. | ||
|
||
: <dfn>relatedOrigins</dfn> | ||
:: The [=WebAuthn Client=] supports [[#sctn-related-origins|Related Origin Requests]]. | ||
</div> | ||
|
||
### User-agent Hints Enumeration (enum <dfn enum>PublicKeyCredentialHints</dfn>) ### {#enum-hints} | ||
|
@@ -4046,7 +4078,62 @@ To override this default policy and indicate that a cross-origin <{iframe}> is a | |
|
||
[=[RPS]=] utilizing the WebAuthn API in an embedded context should review [[#sctn-seccons-visibility]] regarding [=UI redressing=] and its possible mitigations. | ||
|
||
## Using Web Authentication across related origins ## {#sctn-related-origins} | ||
|
||
By default, Web Authentication requires that the [=RP ID=] be equal to the [=determines the set of origins on which the public key credential may be exercised|origin=]'s [=effective domain=], or a [=is a registrable domain suffix of or is equal to|registrable domain suffix=] of the [=determines the set of origins on which the public key credential may be exercised|origin=]'s [=effective domain=]. | ||
|
||
This can make deployment challenging for large environments where multiple country-specific domains are in use (e.g. example.com vs example.co.uk vs example.sg), where alternative or brand domains are required (e.g. myexampletravel.com vs examplecruises.com), and/or where platform as a service providers are used to support mobile apps. | ||
|
||
[=[WRPS]=] can opt in to allowing [=WebAuthn Clients=] to enable a credential to be created and used across a limited set of related [=origin|origins=]. | ||
Such [=[RPS]=] MUST choose a common [=RP ID=] to use across all ceremonies from related origins. | ||
|
||
A JSON document MUST be hosted at the `webauthn` well-known URL ([[!RFC8615]]) for the [=RP ID=]. The JSON document MUST be returned as follows: | ||
timcappalli marked this conversation as resolved.
Show resolved
Hide resolved
timcappalli marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
- The content type MUST be `application/json`. | ||
- The top-level JSON object MUST contain a key named `origins` whose value MUST be an array of one or more strings containing web origins. | ||
|
||
For example, for the RP ID `example.com`: | ||
|
||
<xmp class="json" highlight="json"> | ||
{ | ||
"origins": [ | ||
"https://example.co.uk", | ||
"https://example.de", | ||
"https://example.sg", | ||
"https://example.net", | ||
"https://exampledelivery.com", | ||
"https://exampledelivery.co.uk", | ||
"https://exampledelivery.de", | ||
"https://exampledelivery.sg", | ||
"https://myexamplerewards.com", | ||
"https://examplecars.com" | ||
] | ||
} | ||
</xmp> | ||
|
||
[=WebAuthn Clients=] supporting this feature MUST support at least five [=registrable origin labels=]. Client policy SHOULD define an upper limit to prevent abuse. | ||
|
||
[=WebAuthn Clients=] supporting this feature SHOULD include {{ClientCapability/relatedOrigins}} in their response to [[#sctn-getClientCapabilities|getClientCapabilities()]]. | ||
|
||
### Validating Related Origins ### {#sctn-validating-relation-origin} | ||
|
||
The <dfn abstract-op>related origins validation procedure</dfn>, given arguments |callerOrigin| and |rpIdRequested|, is as follows: | ||
|
||
1. Let |maxLabels| be the maximum number of [=registrable origin labels=] allowed by client policy. | ||
1. Fetch the well-known URL for the RP ID (<code>https://|rpIdRequested|/.well-known/webauthn</code>). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a question about the fetching of the well-known URL. Could this be abused given that the origin of the page that contains the WebAuthn call is necessarily a different origin from the site where the well-known document will be retrieved? This seems to constitute a cross origin request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is the WebAuthn client software fetching the document, not anything in the web session. What types of abuse were you thinking? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nsatragno can you comment based on the discussion on the call?
timcappalli marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. If the fetch fails, the response does not have a content type of `application/json`, or does not have a status code (after following redirects) of 200, then throw a "{{SecurityError}}" {{DOMException}}. | ||
1. If the body of the resource is not a valid JSON object, then throw a "{{SecurityError}}" {{DOMException}}. | ||
1. If the value of the |origins| property of the JSON object is missing, or is not an array of strings, then throw a "{{SecurityError}}" {{DOMException}}. | ||
timcappalli marked this conversation as resolved.
Show resolved
Hide resolved
|
||
1. Let |labelsSeen| be a new empty [=set=]. | ||
1. [=set/For each=] |originItem| of |origins|: | ||
1. Let |url| be the result of running the [=URL parser=] with |originItem| as the input. If that fails, [=continue=]. | ||
1. Let |domain| be the [=effective domain=] of |url|. If that is null, [=continue=]. | ||
1. Let |label| be [=registrable origin label=] of |domain|. | ||
1. If |label| is empty or null, [=continue=]. | ||
1. If the [=set/size=] of |labelsSeen| is greater than or equal to |maxLabels| and |labelsSeen| does not [=set/contain=] |label|, [=continue=]. | ||
1. If |callerOrigin| and |url| are [=same origin=], return [TRUE]. | ||
1. If the [=set/size=] of |labelsSeen| is less than |maxLabels|, [=set/append=] |label| to |labelsSeen|. | ||
1. Return [FALSE]. | ||
|
||
# WebAuthn <dfn>Authenticator Model</dfn> # {#sctn-authenticator-model} | ||
|
||
|
@@ -8616,6 +8703,11 @@ For example: | |
{{CollectedClientData/origin}} to exactly equal some element of a list of allowed origins, | ||
for example the list <code>["https://example.org", "https://login.example.org"]</code>. | ||
|
||
- A web application leveraging [[#sctn-related-origins|related origin requests]] might also require | ||
{{CollectedClientData/origin}} to exactly equal some element of a list of allowed origins, | ||
for example the list <code>["https://example.co.uk", "https://example.de", "https://myexamplerewards.com"]</code>. | ||
This list will typically match the origins listed in the well-known URI for the [=RP ID=]. See [[#sctn-related-origins]]. | ||
|
||
- A web application served at a large set of domains that changes often might parse | ||
{{CollectedClientData/origin}} structurally and require that the URL scheme is <code>https</code> | ||
and that the authority equals or is any subdomain of the [=RP ID=] - for example, | ||
|
Uh oh!
There was an error while loading. Please reload this page.