Skip to content

Commit

Permalink
Merge pull request #1930 from w3c/issue-1889-clarify-origin-matching
Browse files Browse the repository at this point in the history
Add security consideration section "Validating the origin of a credential"
  • Loading branch information
emlun authored Aug 16, 2023
2 parents 84ef4ac + 5ecbf28 commit 0a59b62
Showing 1 changed file with 68 additions and 2 deletions.
70 changes: 68 additions & 2 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -5319,7 +5319,13 @@ In order to perform a [=registration ceremony=], the [=[RP]=] MUST proceed as fo
1. Verify that the value of <code>|C|.{{CollectedClientData/challenge}}</code> equals
the base64url encoding of <code>|options|.{{PublicKeyCredentialCreationOptions/challenge}}</code>.

1. Verify that the value of <code>|C|.{{CollectedClientData/origin}}</code> matches the [=[RP]=]'s [=origin=].
<!-- Note: this next step is actually a top-level step, but bikeshed wanted it indented this much in order to render it as
a numbered step. If outdented, it (today) is rendered as a bullet in the midst of a numbered list :-/
-->
<li id='rp-op-registering-a-new-credential-step-origin'>
Verify that the value of <code>|C|.{{CollectedClientData/origin}}</code> is an [=origin=] expected by the [=[RP]=].
See [[#sctn-validating-origin]] for guidance.
</li>

1. If <code>|C|.{{CollectedClientData/topOrigin}}</code> is present:

Expand All @@ -5328,6 +5334,7 @@ In order to perform a [=registration ceremony=], the [=[RP]=] MUST proceed as fo

1. Verify that the value of <code>|C|.{{CollectedClientData/topOrigin}}</code> matches the [=origin=] of a page
that the [=[RP]=] expects to be sub-framed within.
See [[#sctn-validating-origin]] for guidance.

1. Let |hash| be the result of computing a hash over <code>|response|.{{AuthenticatorResponse/clientDataJSON}}</code> using SHA-256.

Expand Down Expand Up @@ -5540,7 +5547,8 @@ In order to perform an [=authentication ceremony=], the [=[RP]=] MUST proceed as
a numbered step. If outdented, it (today) is rendered as a bullet in the midst of a numbered list :-/
-->
<li id='rp-op-verifying-assertion-step-origin'>
Verify that the value of <code>|C|.{{CollectedClientData/origin}}</code> matches the [=[RP]=]'s [=origin=].
Verify that the value of <code>|C|.{{CollectedClientData/origin}}</code> is an [=origin=] expected by the [=[RP]=].
See [[#sctn-validating-origin]] for guidance.
</li>

1. If <code>|C|.{{CollectedClientData/topOrigin}}</code> is present:
Expand All @@ -5549,6 +5557,7 @@ a numbered step. If outdented, it (today) is rendered as a bullet in the midst o

1. Verify that the value of <code>|C|.{{CollectedClientData/topOrigin}}</code> matches the [=origin=] of a page
that the [=[RP]=] expects to be sub-framed within.
See [[#sctn-validating-origin]] for guidance.

<!-- Note: this next step is actually a top-level step, but bikeshed wanted it indented this much in order to render it as
a numbered step. If outdented, it (today) is rendered as a bullet in the midst of a numbered list :-/
Expand Down Expand Up @@ -8343,6 +8352,63 @@ but is not an exhaustive list.
within the [=scope=] of its [=public key credentials=].


### Validating the origin of a credential ### {#sctn-validating-origin}

When [registering a credential](#rp-op-registering-a-new-credential-step-origin) and
when [verifying an assertion](#rp-op-verifying-assertion-step-origin),
the [=[RP]=] MUST validate the {{CollectedClientData/origin}} member of the [=client data=].

The [=[RP]=] MUST NOT accept unexpected values of {{CollectedClientData/origin}},
as doing so could allow a malicious website to obtain valid [=credentials=].
Although the [=scope=] of [=WebAuthn credentials=] prevents their use on domains
outside the [=RP ID=] they were registered for,
the [=[RP]=]'s origin validation serves as an additional layer of protection
in case a faulty [=authenticator=] fails to enforce credential [=scope=].
See also [[#sctn-code-injection]] for discussion of potentially malicious subdomains.

Validation MAY be performed by exact string matching or any other method as needed by the [=[RP]=].
For example:

- A web application served only at <code>https://example.org</code> SHOULD require
{{CollectedClientData/origin}} to exactly equal <code>https://example.org</code>.

This is the simplest case, where {{CollectedClientData/origin}} is expected
to be the string <code>https://</code> followed by the [=RP ID=].

- A web application served at a small number of domains might require
{{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 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,
<code>example.org</code> or any subdomain of <code>example.org</code>).

Note: See [[#sctn-code-injection]] for a discussion of the risks of allowing any subdomain of the [=RP ID=].

- A web application with a companion native application might allow
{{CollectedClientData/origin}} to be an operating system dependent
identifier for the native application. For example, such a [=[RP]=] might require that
{{CollectedClientData/origin}} exactly equals some element of the list
<code>["https://example.org", "example-os:appid:204ffa1a5af110ac483f131a1bef8a841a7adb0d8d135908bbd964ed05d2653b"]</code>.

Similar considerations apply when validating the {{CollectedClientData/topOrigin}} member of the [=client data=].
When {{CollectedClientData/topOrigin}} is present, the [=[RP]=] MUST validate that its value is expected.
This validation MAY be performed by exact string matching or any other method as needed by the [=[RP]=].
For example:

- A web application that does not wish to be embedded in a cross-origin <{iframe}>
might require {{CollectedClientData/topOrigin}} to exactly equal {{CollectedClientData/origin}}.

- A web application that wishes to be embedded in a cross-origin <{iframe}> on a small number of domains
might require {{CollectedClientData/topOrigin}} to exactly equal some element of a list of allowed origins,
for example the list <code>["https://example-partner1.org", "https://login.partner2-example.org"]</code>.

- A web application that wishes to be embedded in a cross-origin <{iframe}> on a large number of domains
might allow any value of {{CollectedClientData/topOrigin}}, or use a dynamic procedure
to determine whether a given {{CollectedClientData/topOrigin}} value is allowed for a particular ceremony.


# Privacy Considerations # {#sctn-privacy-considerations}

The privacy principles in [[!FIDO-Privacy-Principles]] also apply to this specification.
Expand Down

0 comments on commit 0a59b62

Please sign in to comment.