Feature: Allow RP to opt out of certain transports
My request is related to a high-risk enterprise workforce scenario. As a Relying Party I want to be able to opt-out of the Hybrid transport flow (cross‑device via QR-Code & BLE) within the WebAuthn request. Furthermore, I want to be able to authoritatively check in the WebAuthn response that no Hybrid transports were used during FIDO authentication. To prove this in a reliable way, this has to be part of what is signed.
The reason for this request is, that I see a realistic attack vector described in detail here: https://denniskniep.github.io/posts/14-fido-cross-device-phishing/
Wow, I'm 5 hours late to ask this exact question! 🤯
However, I'd like to add that it would be nice to add integrity protection not only for PublicKeyCredential.authenticatorAttachment, but also for PublicKeyCredentialRequestOptions.allowCredentials, where RPs are also able to forbid hybrid transport from the get-go. As it's currently implemented, an AitM can manipulate both properties (e.g. in a spear phishing attack) and successfully be authenticated via QR-initiated CDA without the RP realizing that the authenticator was even attached cross-platform.
Just like Dennis, I wrote a blog post on this with a demo video (great minds really do think alike, I guess). I'll also be talking about this at this year's German OWASP Day, in case anyone is interested in an in-person discussion.
high-risk enterprise workforce scenario.
In these scenarios, managed contexts should be leveraged to meet your desired workforce security outcomes.
I am not in favor of adding this at the Web Platform layer due to the adverse effects it is likely to have in the greater ecosystem (consumer, unmanaged context).
... the adverse effects it is likely to have in the greater ecosystem (consumer, unmanaged context)
Could you perhaps elaborate on this a bit? What issues would arise from signing one (or both) of these properties or including them in objects that already have integrity protection?
And purely out of curiosity: why are these properties exposed to the RP in the first place if they're not guaranteed to not have been manipulated? Why can an RP limit the transports of the allowed credentials if that limitation can simply be removed by an AitM without anyone ever being able to detect this manipulation?
@LBBO
Could you perhaps elaborate on this a bit? What issues would arise from signing one (or both) of these properties or including them in objects that already have integrity protection?
My response was to the OP, not your proposal.
And purely out of curiosity: why are these properties exposed to the RP in the first place if they're not guaranteed to not have been manipulated?
They are not security properties. They are primarily used to craft user experiences in more advanced use cases.
I think the attack seems legitimate, but I'm not sure it would be solved by, for example, adding a transport value to clientDataJSON.
The attack begins with overriding navigator.credentials.get, so the victim's client isn't involved at all in the WebAuthn ceremony. I don't know in detail how the hybrid transport works, but from skimming the spec it looks to me like the "authenticator" end still acts purely in the authenticator role, and it's still the "client" end that acts as the client, which in particular includes constructing the clientDataJSON value that the authenticator signs. In the attack scenario, this role is performed by the attacker's server, so the attacker can simply lie about any or all of the values in clientDataJSON (indeed, it already lies about origin which is why the attack works in the first place).
So considering that the first step of the attack is to sidestep the WebAuthn API altogether, I don't think there's much we can do within the WebAuthn API to prevent or detect it. I don't know how the hybrid transport protocol could be strengthened to prevent it either - I'd say the authenticator would need to somehow authenticate both the relay server and the client at the other end, but that probably means you can't have the inline setup on first use. But somehow locking down the initial pairing procedure seems to me like one of few possible ways to prevent this.
But yeah, I don't think we could add any signed attribute in WebAuthn that would make the attack preventable or detectable, since the attacker completely sidesteps WebAuthn and is in full control of what's being signed.
~~I can currently think of only one workaround that'll work with no spec or implementation changes: require attestation, and only allow authenticators that are known to not support the hybrid transport (i.e., only built-in, USB and NFC). That would ensure that the victim's client can't be sidestepped in this way, since the attacker won't have connectivity to the authenticator.~~
It's also important to remember that WebAuthn and passkeys are designed to prevent remote phishing attacks. Physical proximity attacks are largely outside the threat model. That said, there is additional work happening to evolve the FIDO Cross-Device Authentication experience.
Also, if the client or client platform is compromised, most other bets are off. There are other ways to mitigate risks in high assurance workforce scenarios, which are largely outside the scope of the WebAuthn specification.
@timcappalli
Physical proximity attacks are largely outside the threat model.
Makes sense. If that means that WebAuthn won't consider any changes aimed at preventing such attacks, the rest of my comment is irrelevant. But I think WebAuthn could be modified to prevent the attacks described by @denniskniep and me, so I'll share my thoughts just in case my suggestions end up being acceptable after all.
Also, if the client or client platform is compromised, most other bets are off.
To me this feels different than a compromised client. I understand that most bets are off if there's malware running on the victim's client. But in this scenario, the victim's client is completely uncompromised. The authenticator is simply communicating with a different client than the victim thinks it is. While this is unimaginable for platform-attached authenticators and probably even for other transports used by cross-platform-attached authenticators, it's now suddenly feasible and it might be worth considering it separately from "ordinary" compromised clients.
@emlun
I'm not sure it would be solved by, for example, adding a transport value to clientDataJSON
Yeah, I guess modifying clientDataJSON wouldn't work. But since the authenticator knows how it's communicating with the client, couldn't it add that information to its response (e.g. by using one or more of the reserved flags in authenticatorData)?
Another option could be promote allowCredentialDescriptorList to a security property, add it to the authenticator's signature and require the authenticator to validate the listed transports before completing the authentication. That way an AitM could either add the hybrid transport to the allow-list, but that manipulation would then be detected by the RP, or the AitM doesn't add it and the authenticator refuses to complete authentication because an unallowed transport is being used.
But since the authenticator knows how it's communicating with the client,
That is only the case for traditional authenticators using external transports (USB, NFC, Bluetooth), not for software-based credential managers.
To me this feels different than a compromised client.
I brought this up because you mentioned wanting to sign attributes relating to the transports. That seems to stem from the assumption that you don't trust the client.
@emlun
I can currently think of only one workaround that'll work with no spec or implementation changes: require attestation, and only allow authenticators that are known to not support the hybrid transport (i.e., only built-in, USB and NFC).
I tested it with a Security Key on Android and it worked. So it works also with authenticators that are known to not support the hybrid transport (see https://denniskniep.github.io/posts/14-fido-cross-device-phishing/#security-keys-also-affected)
But yeah, I don't think we could add any signed attribute in WebAuthn that would make the attack preventable or detectable, since the attacker completely sidesteps WebAuthn and is in full control of what's being signed.
As you said this attack acts as CTAP client and is in full control what he sends to the Authenticator (e.g. origin). The Authenticator receives the crafted CTAP messages. But this attack is not in control of the Authenticator on the other side of the TunnelServer.
Maybe the CTAP client is not directly connected to the final Authenticator. It could be that there is e.g. an OS Credential "Router" (does this has an official name?) in between. I guess that is what @timcappalli was referring to:
That is only the case for traditional authenticators using external transports (USB, NFC, Bluetooth), not for software-based credential managers.
Example 1: Directly connected
.get() --webAuthnReq---> [CTAP Client] --CTAP Msg--> [TunnelServer] --CTAP Msg--> [Authenticator]
Example 2: OS Credential "Router"
.get() --webAuthnReq---> [CTAP Client] --CTAP Msg--> [TunnelServer] --CTAP Msg--> [OS Credential "Router"] --CTAP Msg--> [Authenticator]
Because this attack can not control the execution of the components on the other end of the Tunnel Server, we might be able to leverage that situation to better secure that scenario.
What if the listener that is connected to the TunnelServer (e.g. OS Credential "Router" or Authenticator - see above examples) are adding to the CTAP message flow a signal that hybrid was used.
This signal will then be part of the signature e.g. as proposed here by @LBBO
But since the authenticator knows how it's communicating with the client, couldn't it add that information to its response (e.g. by using one or more of the reserved flags in authenticatorData)?
Now the webAuthnResponse contains a verifiable proof that hybrid was used, independent of the actually used Authenticator.
The RelyingParty is now able to reject the authentication.
My request is related to a high-risk enterprise workforce scenario. As a Relying Party I want to be able to opt-out of the Hybrid transport flow (cross‑device via QR-Code & BLE) within the WebAuthn request. Furthermore, I want to be able to authoritatively check in the WebAuthn response that no Hybrid transports were used during FIDO authentication. To prove this in a reliable way, this has to be part of what is signed.
The only viable option is attestation - this allows you to precisely control the authenticators in use.
The only viable option is attestation - this allows you to precisely control the authenticators in use
@Firstyear why should that technically prevent the hybrid flow?
From my point of view the Authenticator is not necessarily aware how the CTAP messages are transported to the Authenticator. Even if its an attested USB Security Key, CTAP Messages might be relayed by the Operating System through a different channel beforehand (hybrid flow) and finally sent via USB to the Security Key.
I tested exactly that scenario on Android. After you scanned the qr code with your Android phone you are able to select a Security Key to complete the authentication.
@denniskniep How did you test this on Android? My understanding was that CTAP forwarding from hybrid to usb transports was not allowed on Android, and when I retested this just now on my Pixel device I am not offered to use my security key after scanning the QR-encoded FIDO uri (unless I use a credential provider that explicitly features this forwarding).
@joostd here is how I can reproduce it. Use allowedCredentials: [] within the webAuthN request. This requires that the security key is registered as resident key.
- started fido authentication on Laptop and choose hybrid flow
- scanned the QR code with my android (also a pixel device)
- clicked on "more options"
- clicked "Use a different device"
- clicked on "USB security key"
-
Tap the security key and enter Pin
-
authentication completes on the Laptop
Thanks @denniskniep , I am now able to reproduce. I was missing the "More Options" link in the first screen, but using a specific order I can now authenticate using a passkey stored on a security key.
Interestingly,
- I can only authenticate using the security key if I also have a passkey stored in Google Password Manager
- I can only authenticate using the security key if allowCredentials is empty
- I can only authenticatie using this flow, but not register
I also noticed a warning "Only connect to devices you trust" on Android after scanning the QR code and before connecting to the client that I think wasn't there before. This is a good addition but I am not sure if this will help against phishing attacks where users already believe they are using a trusted client.
I have also wondered if Relying Parties can discourage (instead of prevent) hybrid flows by disabling hybrid or detecting if hybrid was used after the fact and present a warning in the hope of making them (edit: ie users) more aware of future phishing attempts. For instance:
- In the get() and create() publicKey hints options, exclude "hybrid": hints: ["security-key", "client-device"]
- When registering a credential, detecting credentials with attachment 'cross-platform' that also have transports that include 'hybrid'.
- When authenticating, detecting assertions for credentials with attachment 'cross-platform' that reported 'hybrid' transport during registration.
Unfortunately, authenticatorAttachment does not behave consistently across browsers. See for instance this Safari issue.
To me this feels different than a compromised client. I understand that most bets are off if there's malware running on the victim's client. But in this scenario, the victim's client is completely uncompromised.
Yeah, I agree we can't simply dismiss this with "compromised client is outside the threat model". The only thing the victim does wrong in this scenario is use a benevolent client to visit a malicious website - exactly the scenario that WebAuthn's phishing protection is meant to address.
Yeah, I guess modifying
clientDataJSONwouldn't work. But since the authenticator knows how it's communicating with the client, couldn't it add that information to its response (e.g. by using one or more of the reserved flags in authenticatorData)?
Hm, yeah, the authenticator definitely could add signals like this. Using an authenticatorData flag for this seems disproportionate, but it's definitely possible to add this data as an authenticator extension. That wouldn't help at all for any currently existing non-upgradable security keys, though.
Either way, I don't think that just adding a detection mechanism is the right way to go. The proper solution should be to either eliminate the vulnerability from the transport, or drop the transport altogether. Because that would be the use for the detection anyway, right?: forbid the hybrid transport altogether on the RP side, since the RP doesn't know whether or not it was used maliciously. Any existing RP implementations that don't update to check the new detection mechanism get no benefit, so their users are still susceptible to the attack. Conversely, if the vulnerability does get fixed, then users would remain unable to use the hybrid transport until RPs update their implementations to no longer forbid it. And finally: even newly manufactured security keys wouldn't have any idea about being proxied over hybrid unless the proxying platform adds a hint about that in its input to the authenticator - so then we're modifying the hybrid protocol anyway, so we might as well address the vulnerability directly instead.
So a detection signal seems like a very unwieldy solution for a problem that will hopefully end up being temporary. Ideally it should be enough for the user to update their client (and possibly smartphone OS) to get whatever countermeasure we end up with.
Unfortunately I think all of that also means (if we assume that my assessment and opinion is objectively correct 😇) that we can't feasibly expect much visibility for RPs to tell once a fix has been rolled out, either. We can't update existing security keys, so we can't assume a signal from the authenticator. We could bundle a transport fix with a clientDataJSON attribute that signals the client is using some new hybrid protocol version that fixes the issue (and an attacker couldn't lie about this attribute because the new protocol wouldn't give the attacker an opportunity to connect to the authenticator), but then that signal would of course only be present when the issue is fixed, so the RP could only differentiate between "not vulnerable (used non-hybrid transport or fixed hybrid)" and "maybe vulnerable (used non-hybrid transport or vulnerable hybrid)", which doesn't help much.
So yeah, I think that even just adding a signal for detecting the hybrid transport would still effectively require changes to the hybrid protocol, so to me it doesn't seem very useful to look for mitigations other than just eliminating the vulnerability in the first place.
I agree that clientDataJSON seems to be a better place than authenticatorData for such kind of fix as the authenticator might not even be aware of hybrid being used. The issue might not be as relevant in case UWB will be used for hybrid with an ability to determine/limit the acceptable maximum distance between the two devices.
There's a similar class of vulnerabilities (assuming you have a bluetooth beacon in place) for classic bluetooth authenticators. I think in that case you might be able to get away with attestation to reject those because there's no forwarding for classic bluetooth the way it exists for hybrid.
We could have the device scanning the QR code inject something that gets signed by the authenticator. But as @emlun says, trying to detect this seems like the wrong approach. It's possible there's not a lot we can do considering the BLE advert is key to underpinning the security of the protocol.
I agree that clientDataJSON seems to be a better place than authenticatorData for such kind of fix as the authenticator might not even be aware of hybrid being used.
Given this is built by the client (browser) not the authenticator, a compromised client can just say "I used usb, promise" even if it was hybrid.
The only viable option is attestation - this allows you to precisely control the authenticators in use
@Firstyear why should that technically prevent the hybrid flow?
From my point of view the Authenticator is not necessarily aware how the CTAP messages are transported to the Authenticator. Even if its an attested USB Security Key, CTAP Messages might be relayed by the Operating System through a different channel beforehand (hybrid flow) and finally sent via USB to the Security Key.
Correct, and it's possible to shim a usb CTAP key over caBLE.
Now what you need to step back and consider is this - what is your threat model.
At the moment, you are focused on the transport layer of how the signed response is sent. However, I'm going to challenge you that even over HTTP a webauthn assertion (nav.cred.get) is secure. The reason is that from the RP you send a nonce that you want the authenticator to sign. The authenticator signs this nonce and returns the signed data.
If the nonce was altered from the RP -> Authenticator, the Authenticator will sign the wrong data and your RP will then be able to assert that the operation failed.
If the response from the Authenticator -> RP is altered or tampered with, the signature will fail.
If the response from the Authenticator -> RP is replayed from an earlier assertion, the RP will reject the operation as the nonce is not the one it requested to be signed.
So the transport layer doesn't matter. Even plain text, the assertion can't be falsified. I think your concern over what transport is used is not one that will affect the security of the system.
Now we turn our attention to the more important part of this - the real reason attestation is what matters in a high security environment is that it's the only way to cryptographically verify how and where the private key of the authenticator is stored.
Without attestation, the private key could be stored on a post-it note attached to someone's monitor. Attestation is the only way to demand a proof that the private key is stored in a hardware secure enclave where it can't be exfiltrated or removed. It also allows you to prove and trust that signals like UV will be performed correctly, and not falsified.
So I hope that this helps to explain why first, you want and need attestation, and second, why the transport in use doesn't matter.
@Firstyear I don't quite follow.
So I hope that this helps to explain why first, you want and need attestation, and second, why the transport in use doesn't matter.
Attestation increases trust in the authenticator, but the issue is that for phishing resistance you need a trusted client. The issue here is that when using hybrid transport, an attacker can trick users into connecting their authenticator to an untrusted client. The authenticator nor the Relying Party can currently detect this, as all messages exchanged between both Client and Authenticator and Client and Relying Party are similar whether the attack is taking place or not. Preventing the attack relies on the users being cautious when connecting their device to their client, making sure they are not inadvertently connecting to the wrong client.
There's a similar class of vulnerabilities (assuming you have a bluetooth beacon in place) for classic bluetooth authenticators. I think in that case you might be able to get away with attestation to reject those because there's no forwarding for classic bluetooth the way it exists for hybrid.
I was incorrectly assuming there was no forwarding of CTAP messages from hybrid transport to usb transport on Android either.
@nsatragno Has that always been the case or is that a recent addition? And am I correct that this is a feature of Google Password Manager?
Given the following obervations (please correct me where I'm wrong):
- Hybrid flow has been introduced to enable platform authenticators to be used cross-device.
- The attack described here is not new (see for instance @agl's excellent Tour of WebAuthn, section "Threats"), instead hybrid flow was designed to sacrifice a bit of security for increased usability. In other words: FIDO credentials are still phishing-resistant, but hybrid flow introduces a small attack vector that can only be launched from within the vicinity of a victim (as opposed to the whole of the Internet with traditional passwords)
- Security keys do not need the hybrid flow, as they are designed to be used cross-device.
Would it make sense to disable the use of security keys when using hybrid transport, as there is no strong use-case for it?
What if the WebAuthn responses were sent directly to the Relying Party through a pre-established backchannel? This way, any potential attacker-in-the-middle would never have access to the response data at all.
During the WebAuthn credential creation ceremony, the Relying Party could provide a backchannel URI to which the client platform would later deliver the WebAuthn response directly.
Would introducing such a mechanism be a possible extension or modification within CTAP, or would it conflict with the current architecture principles?
What if the WebAuthn responses were sent directly to the Relying Party through a pre-established backchannel?
This would effectively be federation then. Credential managers / authenticators in a consumer context do not have a direct relationship with Relying Parties by design. Changing that would essentially be designing a new protocol stack.
@ntrojanowska Unfortunately that would not prevent this attack. The main part of the attack happens before the authenticator generates the response: the malicious client sets the RP ID to a different value than the one for the page the user navigated to. That causes the authenticator to sign over the "correct" RP ID and clientDataJSON.origin, so even if the result was sent directly back to the RP, the RP would accept the assertion with no indication that anything went wrong.
And no, making the authenticator connect directly to the RP to initiate the ceremony also wouldn't help, it would make things worse: then a malicious actor wouldn't even need to trick the victim into loading a malicious webpage, instead they could just ping the server to make it pop an authentication request on the victim's authenticator. For example, the Swedish BankID system had this exact vulnerability and there's been lots of organized fraud using variants of this attack. WebAuthn's requirement that the ceremony is mediated through a client on the user's device is a critical component of preventing these kinds of attacks (and is precisely why the attack in this thread begins with sidestepping the WebAuthn API altogether).
Just to try to bring this discussion back around, @denniskniep if you believe you discovered a protocol vulnerability in FIDO CTAP, please send the details to [email protected]. That discussion should not continue here as CTAP is not defined by the W3C Web Authentication WG.
I recommend we keep this issue to its original topic which (I believe) is a feature request for WebAuthn to provide the ability to limit which transports are used.
@nsatragno Has that always been the case or is that a recent addition? And am I correct that this is a feature of Google Password Manager?
It's a GPM feature.
Either way, I don't think that just adding a detection mechanism is the right way to go. The proper solution should be to either eliminate the vulnerability from the transport, or drop the transport altogether.
While eliminating the vulnerability from the transport would be optimal, I'm really unsure how this could possibly work. The BLE connection between the client and the authenticator can't be verified directly by regular users. Unless I'm missing something, the verification process would need to work via some system-level UI (e.g. entering some verification code), but wouldn't that also be spoofable by the phishing page (at least to an extent where regular users wouldn't recognize that they're not dealing with a system-level UI)? I can't think of a solution to that problem, but that may very well be a lack of creativity or knowledge on my part.
So assuming that the CTAP issue won't be fixed any time soon, we're left with removing the transport or introducing an opt-out mechanism. I believe the transport should definitely stay available for most use cases because most use cases don't have threat models that include in-person attackers. And the convenience can be amazing e.g. for signing in on smart TVs. So I think an opt-out feature would be a great compromise.
So wouldn't it be possible to implement an opt-out feature using a combination of WebAuthn and CTAP? WebAuthn could allow RPs to restrict the used transports (with integrity protection) and require authenticators to adhere to the RP's restriction. CTAP could specify that whatever system on the authenticator's device ends up performing the hybrid transport must inform the authenticator that this transport was used. The authenticator would then be able to make a definitive decision on whether to allow the process to continue or not based on the RP's restrictions and the knowledge about what transport was used.
The problem is that without signed requests an attacker can change the request.
We could require the selector to pass the transport to the authenticator to include in client data or include it in client data directly depending on architecture.
The RP would be responsible for rejecting authentications that don't meet its requirements.
When that came up about a year ago this was rejected by the platforms because it would potentially cause large numbers of legitimate transactions to be rejected by RP.
Other ways of signalling risk were considered but not acted on at the time.
Dynamic QR codes were discussed and rejected because of deployment practicalities. They would only reduce attack surface not stop the attack.
The problem/opportunity is that Hybrid was originally between your desktop and your phone. Users did not expect it in other situations. Now if we expand that to other in person presentment to kiosks etc people will become used to using it in situations where it could be dangerous if they are not paying close attention to who the presented RP is, or the context of the authentication.
Ideally we can find a protocol way to mitigate this.
I agree to John here. Hybrid protocol initially was designed for a limited set of use cases. But as these use cases expand - rather than trying the band-aid solution we all can sit together and solve it on a protocol level (with the expanded problem statement).