When deploying a service based on the WebAuthn Starter kit, there are a number of tangential security elements to be aware of. While outside the scope included in the WebAuthn Starter Kit and WebAuthn authentication flows, aspects of the greater environment in an actual deployment may introduce potential avenues to bypass the protections therein.
Cross-origin resource sharing (CORS) is a browser security feature that restricts cross-origin HTTP requests that are initiated from scripts running in the browser. The WebAuthn Starter kit is created to offer an abundance of flexibility in how it can be deployed to other systems. As such, the Cross-Origin Resource Sharing (CORS) header defaults to everywhere. In an actual deployment, this should obviously be restricted to only the needed origins.
For typical deployments, the CORS header would include only ‘companyname.com` and www.companyname.com
at a minimum for a javascript web client making requests to the Lambda. For further reference, refer to AWS’ documentation on this subject:
Enabling CORS for a REST API resource.
When deploying WebAuthn, one of the key flows to consider is the user’s recovery of their account should their authenticator become lost or stolen. There are multiple avenues to addressing this, from policies such as requiring multiple authenticators per account, to recovery authentication flows built into a service. The correct approach for Account Recovery is highly dependent on the security and sensitivity of the data protected. Regardless, it is important that the account recovery flow is well protected; malicious actors attempting to gain access to protected accounts will bypass a strong primary form of authentication if they can utilize the lesser-protected account recovery functions instead.
The WebAuthn Starter kit offers a very basic account recovery flow, with the intent of demonstrating how to enable such a flow into a WebAuthn integration. For deployments, we recommend using an existing account recovery option is already in place for a service, if one already exists.
For new services, the Digital Identity Guidelines published by the National Institute of Standards and Technology provide an excellent resource on mitigating the risks to account recovery.
The WebAuthn standard level 2 editor’s draft includes the section §14. Privacy Considerations. This section describes in depth the privacy aspects of WebAuthn.
For the WebAuthnKit in particular, the privacy concerns addressed in section §14.6.2. Username Enumeration in conjunction with §14.6.3. Privacy leak via credential IDs need to be considered.
The most relevant part from section §14.6.2. Username Enumeration is copied below:
While initiating a
registration or
authentication ceremony, there is a risk that the
WebAuthn Relying Party might leak sensitive information about its registered users. For example, if a
Relying Party uses e-mail addresses as usernames and an attacker attempts to initiate an
authentication ceremony for alex.p.mueller@example.com
and the
Relying Party responds with a failure, but then successfully initiates an
authentication ceremony for j.doe@example.com
, then the attacker can conclude that j.doe@example.com
is registered and alex.p.mueller@example.com
is not.
If, when initiating an authentication ceremony, there is no account matching the provided username, continue the ceremony by invoking `navigator.credentials.get()` using a syntactically valid `PublicKeyCredentialRequestOptions` object that is populated with plausible imaginary values.
This approach could also be used to mitigate information leakage via allowCredentials
; see
§13.5.6 Unprotected account detection and
§14.6.3 Privacy leak via credential IDs."
The most relevant part from section §14.6.3. Privacy leak via credential IDs is copied below:
This privacy consideration applies to Relying Parties that support authentication ceremonies with a non- empty `allowCredentials` argument as the first authentication step. For example, if using authentication with server-side credentials as the first authentication step.
In order to prevent such information leakage, the Relying Party could for example:
Perform a separate authentication step, such as username and password authentication or session cookie authentication, before initiating the WebAuthn authentication ceremony and exposing the user’s credential IDs.
Use client-side discoverable credentials, so the `allowCredentials` argument is not needed.
If the above prevention measures are not available, i.e., if `allowCredentials` needs to be exposed given only a username, the Relying Party could mitigate the privacy leak using the same approach of returning imaginary credential IDs as discussed in §14.6.2 Username Enumeration."
This section describes the solutions that are implemented in the WebAuthn Starter Kit to mitigate the privacy leaks.
The Recommendation in section §14.6.3. Privacy leak via credential IDs:
Use client-side discoverable credentials, so the `allowCredentials` argument is not needed.
In short, the allowCredentials
argument should be left empty when dealing with client-side discoverable credentials.
This recommendation is relevant for the WebAuthnKit for the User-Verified flow, in the case where a FIDO authenticator with client-side discoverable credentials is used. The WebAuthnKit returns an empty list of allowCredentials
, preventing a malicious actor from identifying which accounts are secured with WebAuthn client-side discoverable credentials and which are not, and potentially easier to attack.
The Recommendation in section §14.6.3. Privacy leak via credential IDs:
Perform a separate authentication step, such as username and password authentication or session cookie authentication, before initiating the WebAuthn authentication ceremony and exposing the user’s credential IDs.
This recommendation is relevant for the WebAuthnKit for the U2F with Password flow. This is not supported by the WebAuthnKit for the U2F with Password flow, where the user is first authenticated with their WebAuthn credential then with a U2F Password. Credential ID’s associated to a user would be exposed by the allowCredentials property in the PublicKeyCredentials response from the server.
The Recommendation in section §14.6.2. Username Enumeration:
If, when initiating an authentication ceremony, there is no account matching the provided username, continue the ceremony by invoking `navigator.credentials.get()` using a syntactically valid `PublicKeyCredent ialRequestOptions` object that is populated with plausible imaginary values.
This recommendation is relevant for the WebAuthnKit for the U2F with Password flow—however, this is not yet fully supported by the WebAuthnKit for the U2F with Password flow. Currently, the U2F Password authentication begins with the user supplying an identifier. If an identifier does not exist, no WebAuthn ceremony is invoked. Authentication would not be triggered for any other identified users, but that also means that the ceremony is NOT invoked with a response from the RP with imaginary values. This risk can also be mitigated during user registration by not allowing users to identify themselves with email addresses - The motivation behind this is a user may not use the same username across multiple RPs.