Crate webauthn_rs

source ·
Expand description

Webauthn-rs - Webauthn for Rust Server Applications

Webauthn is a standard allowing communication between servers, browsers and authenticators to allow strong, passwordless, cryptographic authentication to be performed. Webauthn is able to operate with many authenticator types, such as U2F, TouchID, Windows Hello and many more.

This library aims to provide a secure Webauthn implementation that you can plug into your application, so that you can provide Webauthn to your users.

There are a number of focused use cases that this library provides, which are described in the WebauthnBuilder and Webauthn struct.

Getting started

In the simplest case where you just want to replace passwords with strong self contained multifactor authentication, you should use our passkey flow.

use webauthn_rs::prelude::*;

let rp_id = "example.com";
let rp_origin = Url::parse("https://idm.example.com")
    .expect("Invalid URL");
let mut builder = WebauthnBuilder::new(rp_id, &rp_origin)
    .expect("Invalid configuration");
let webauthn = builder.build()
    .expect("Invalid configuration");

// Initiate a basic registration flow to enroll a cryptographic authenticator
let (ccr, skr) = webauthn
    .start_passkey_registration(
        Uuid::new_v4(),
        "claire",
        "Claire",
        None,
    )
    .expect("Failed to start registration.");

After this point you then need to use finish_passkey_registration, followed by start_passkey_authentication and finish_passkey_authentication

No other authentication factors are needed! A passkey combines inbuilt user verification (pin, biometrics, etc) with a hardware cryptographic authenticator.

Tutorial

Tutorials and examples on how to use this library in your website project is on the project github https://github.com/kanidm/webauthn-rs/tree/master/tutorial

What is a “Passkey”?

Like all good things - “it depends”. Mostly it depends who you ask, and at what time they adopted the terminology. There are at least four definitions that we are aware of. A passkey is:

  • any possible webauthn authenticator - security key, tpm, touch id, etc
  • a platform authenticator - built into a device such as touch id, tpm, etc
  • a synchronised credential - backed by a cloud keychain like Apple iCloud
  • a resident key - a stored, discoverable credential allowing usernameless flows

The issue is each of these definitions have different pros/cons and different implications. For example, passkeys as resident keys means you can accidentally brick many ctap2.0 devices by exhausting their storage. Passkeys as platform authenticators means only certain devices can use them. Passkeys as synced credentials means only certain devices with specific browser combinations can use them.

In this library we chose to define passkey’s as “any possible authenticator”. If the device opportunistically creates rk (such as Apple iCloud Keychain) then in the future we may allow usernameless flows once we are satisfied with the state of these ui’s in browsers.

Features

This library supports some optional features that you may wish to use. These are all disabled by default as they have risks associated that you need to be aware of as an authentication provider.

Allow Serialising Registration and Authentication State

During a webauthn registration or authentication ceremony, a random challenge is produced and provided to the client. The full content of what is needed for the server to validate this challenge is stored in the associated registration or authentication state types. This value MUST be persisted on the server. If you store this in a cookie or some other form of client side stored value, the client can replay a previous authentication state and signature without possession of, or interaction with the authenticator, bypassing pretty much all of the security guarantees of webauthn. Because of this risk by default these states are not allowed to be serialised which prevents them from accidentally being placed into a cookie.

However there are some safe cases of serialising these values. This includes serialising to a database, or using a cookie “memory store” where the client side cookie is a key into a server-side map or similar. Any of these prevent the replay attack threat.

An alternate but “less good” method to mitigate replay attacks is to associate a very short expiry window to the cookie if you need full client side state, but this may still allow some forms of real time replay attacks to occur. We do not recommend this.

Enabling the feature danger-allow-state-serialisation allows you to re-enable serialisation of these types, provided you accept and understand the handling risks associated.

Credential Internals and Type Changes

By default the type wrappers around the keys are opaque. However in some cases you may wish to migrate a key between types (security key to passkey, attested_passkey to passkey) for example. Alternately, you may wish to access the internals of a credential to implement an alternate serialisation or storage mechanism. In these cases you can access the underlying Credential type via Into and From by enabling the feature danger-credential-internals. The Credential type is exposed via the prelude when this feature is enabled.

However, you should be aware that manipulating the internals of a Credential may affect the usage of that Credential in certain use cases. You should be careful when enabling this feature that you do not change internal Credential values.

User-Presence only SecurityKeys

By default, SecurityKeys will opportunistically enforce User Verification (Such as a PIN or Biometric). This can cause issues with Firefox which only supports CTAP1. An example of this is if you register a SecurityKey on chromium it will be bound to always perform UserVerification for the life of the SecurityKey precluding it’s use on Firefox.

Enabling the feature danger-user-presence-only-security-keys changes these keys to prevent User Verification if possible. However, newer keys will confusingly force a User Verification on registration, but will then not prompt for this during usage. Some user surveys have shown this to confuse users to why the UV is not requested, and it can lower trust in these tokens when they are elevated to be self-contained MFA as the user believes these UV prompts to be unreliable and not verified correctly - in other words it trains users to believe that these prompts do nothing and have no effect. In these cases you MUST communicate to the user that the UV may occur on registration and then will not occur again, and that is by design.

If in doubt, do not enable this feature.

‘Google Passkey stored in Google Password Manager’ Specific Workarounds

Android (with GMS Core) has a number of issues in the dialogs they present to users for authenticator selection. Instead of allowing the user to choose what kind of passkey they want to use and create (security key, device screen unlock or ‘Google Passkey stored in Google Password Manager’), Android expects every website to implement their own selection UI’s ahead of time so that the RP sends the specific options to trigger each of these flows. This adds complexity to RP implementations and a large surface area for mistakes, confusion and inconsistent workflows.

By default for maximum compatibility and the most accessible user experience this library sends the options to trigger security keys and the device screen unlock as choices. As RPs must provide methods to allow users to enroll multiple independent devices, we consider that this is a reasonable trade since we allow the widest possible sets of authenticators and Android devices (including devices without GMS Core) to operate.

To enable the registration call that triggers the ‘Google Passkey stored in Google Password Manager’ key flow, you can enable the feature workaround-google-passkey-specific-issues. This flow can only be used on Android devices with GMS Core, and you must have a way to detect this ahead of time.

Modules

  • A prelude of types that are used by Webauthn

Structs

  • An instance of a Webauthn site. This is the main point of interaction for registering and authenticating credentials for users. Depending on your needs, you’ll want to allow users to register and authenticate with different kinds of authenticators.
  • A constructor for a new Webauthn instance. This accepts and configures a number of site-wide properties that apply to all webauthn operations of this service.