Passkeys are single factor, and why that's (mostly) okay

I have once again awoken and chosen to cause a kerfuffle. Now to save you reading the whole post I will give you the conclusion now:

Passkeys are single factor, except when they are not. And that mostly doesn't matter. Until it does.

You can fight amongst yourselves as to which camp you belong in.

Origin of Multi Factor Authentication

To understand why Multi Factor Authentication (MFA) is often mandated, we have to remember how we got here. In the dark ages, we used to only use passwords as a credential when accessing systems. However passwords have a lot of weaknesses, and even if you have the best password in the world then there are still plenty of attacks against them.

The best article to explain this is the excellent Your Password Doesn't Matter which describes attacks on passwords, and why MFA is so important.

This has led to the rise of time based one-time password (TOTP) and universal second factor (U2F). Mostly you will likely have interacted with TOTP more than U2F just due to it's lower bar of availability.

Inevitably plenty of auditors and regulators now mandate the enforcement of MFA for authentication. And of course because of this Passkeys have to be MFA to be acceptable for use.

How Passkeys Implement MFA

To understand why Passkeys are single factor we first have to understand how they ... well implement MFA.

During authentication with a Passkey (aka authenticator), the relying party (RP, aka who wants to verify you) sends a challenge to your device. This challenge has a number of parameters including a request for you the user to verify yourself to the authenticator. The requirement can be one of:

  • discouraged - no verification needed
  • preferred - verify if the authenticator is capable, else continue without verification
  • required - verification must be performed

So how does this verification work?

Lets say you have a yubikey and our challenge contains user verification = required. Now our yubikey needs us to supply a PIN value which the secure enclave (SE) of the yubikey validates in addition to our need to touch the key to prove our physical presence with the device.

If the PIN is wrong, the key refuses to proceed. If we don't touch the key, then the same refusal.

This has a few neat properties.

  • We can't perform a software-only authentication, because we require the user to physically touch the key.
  • Physical theft of the key can't proceed without the PIN as the attacker doesn't know it.
  • Since the PIN is verified by the authenticator, it can implement ratelimits and lockouts.
  • Disassembling the device to try and retrieve the key and PIN would be an exercise in suffering.

This is what makes our security key multi-factor. You require not only physical possession and presence of the authenticator, but knowledge of the PIN. (Side note - other devices may do this with biometrics like a fingerprint reader but it has the same result).

As you may have noticed though this verification happens inside the authenticator. So how do we tell our relying party that this verification happened?

Well our Passkey is based on public-private key cryptography which allows our authenticator to sign the challenge that our RP provided. Then we can send back the signed response (aka assertion) to the RP which uses our public key to determine that it must have been our authenticator that was used.

Now this signed challenge contains quite a bit of data but for our usage here the fields we care about are contained in the authenticator data structure. Specifically what we care about are the flags in position bit 1 and 3.

Bit 1 is user presence. This being set indicates that a physical interaction (such as touch) of the authenticator occured.

Bit 3 is user verification. This being set indicates that the authenticator verified something about the user such as a PIN, biometric or something else.

These fields in the authenticator data structure are signed by the authenticators private key so the RP can then check the signature and verify the bits are set as required. Hooray we have multifactor authentication that validates the user was present and verified!

Or do we ...

Single Factor Variant One - RP's don't verify the bits

The first and simplest variant of this is relying parties that either don't request the right verification options, or simply don't verify the bits even if they do.

For example, if you have an RP that requests preferred user verification, then there is a 99% chance that you can modify this client side to discouraged and completely bypass verification. This is because if you have preferred you have to be able to fall back to the user verification bit as false being a valid response. In this way preferred == discouraged and should never be used. In worse cases, you can alter required to discouraged and still bypass user verification.

And yes I have found large public identity providers that are vulnerable to this, and still are to this day (yes I responsibily disclosed to any vendor I have found, no they don't care).

The second variant is RP's that simply don't give a fuck. For example github when you use a passkey in their "sudo" mode to modify your account/project settings will send discouraged. This means physical theft of the key along with a session cookie is enough to modify anything on the account. Certainly not the ... worst user verification crime, but this really should be required.

Single Factor Variant Two - Lies, Lies, and more Lies.

Finally my favourite class. Authenticators that simply lie about user verification. Password managers tend to fall into this category, but there are some physical keys so terrible that they can probably be exploited to achieve the same.

What this means is when an RP asks for user verification to be required, the password manager simply falsifies the user verification bit, never asks the user for a PIN or other verification, and proceeds happily to sign the challenge.

This means as the RP when you get that authenticator data back and the user verification bit is set, you no longer have a way to trust if it really happened. You only know someone has the private key not that they verified to the authenticator since that bit is now untrustworthy.

This is why Passkeys are Single Factor - and it Mostly Doesn't Matter.

Between RP's that implement Passkeys incorrectly and authenticators that simply lie about user verification it becomes a reasonable assumption that when you receive the user verification bit you just don't know if it can be trusted or not. Or as a user, if the service even checks that correctly.

But lets say your in the majority of use cases such as public consumer facing websites. Does it matter?

Lets draw this back to where we started.

Your Password Doesn't Matter

MFA is only a requirement because passwords are terrible.

The attacks you can pull off against a password don't apply to a Passkey, meaning the level of security you have even with a password manager that lies about user verification is still better than using a password and TOTP ( usability issues not withstanding ).

  • You can't be phished - the uri origin is signed as part of the challenge and verified .... I hope.
  • There are no 'top one hundred most common passkeys' lists you can spray and pray.
  • Database leaks don't reveal the private key - only the public key.
  • And that public key can't be attacked offline like a password hash.
  • Annndddd that public key is unique per website.

So in the end it doesn't matter that Passkeys are (mostly) single factor - the issues that affect passwords don't affect Passkeys making them better than a password even if user verification wasn't performed or checked.

To drive this home: many people store their password and TOTP in the same password manager, so compromise of the password manager would have the same consequences on the "single factor" Passkey as the "multi factor" password and TOTP - you're screwed either way. And I bet that your password manager doesn't perform user verification when you use that password and TOTP either.

But What if it Does Matter?

Now, I will say as someone whose password manager is one of these naughty naughty ones that lies about user verification, there are some times that this does matter.

As an Individual

If you have high value accounts, choose to put them on a yubikey where you know and trust that user verification will be performed and enforced. Some easy examples are:

  • Email accounts
  • Anything which may control the domain name of your email account
  • Banking
  • Government services (holy shit did you know my.gov.au supports Passkeys!!!)
  • Work place authentication

For people who like me tend to work in opensource other good examples

  • Code repository authentication
  • SSH keys
  • Package hosting

Make some informed choices about how much compromise of the service or your password manager would affect you personally (or heck, if it would affect others). If it would be life altering, maybe a physical key is best (since it can't be remotely used or exfiltrated).

But hey, I keep plenty of passkeys in my deceptive password manager. Remember to always have a strong login to your devices, full disk encryption, etc etc. Just make an informed decision about the damage potential of the credential if taken from the password manager. Security is a spectrum after all.

As an Organisation

Enforce attestation on high-value accounts. This forces cryptographic verification of what Passkeys (authenticators) can be registered to your identity provider. This lets you audit the devices first to ensure they behave in a trusted manner before you let them be used as an authenticator. This way when you see the user verification bit you, you know and trust the authenticator really did set it properly. And more importantly that devices you haven't audited aren't allowed to be used in the first place.

Second, audit your identity provider and ensure that even when attestation is enabled it doesn't allow non-attested credentials to register (or even falsified AAGUIDs). Also audit that they send and verify the user verification requirements and bits correctly. Lots of vendors get this wrong, so it's worth verifying these behaviours yourself.

Is This a Yubikey Advert?

No I'm not paid by yubico, but seriously, just throw yubikeys at people like candy. Nothing else comes close today for usability and security.

I have plenty of other keys I've tried and they all have issues. From firmware updates that wipe all your Passkeys away, to defective models that are impossible to trigger the presence on, to the worst that don't even have secure enclaves to store their private keys and LIE to users claiming they DO use the SE.

So yeah, just get yubikeys.

Conclusion

As promised:

Passkeys are single factor, except when they are not. And that mostly doesn't matter. Until it does.