Mitigating a same-device / cross-device security issue
There are security issues with same-device and cross-device flows where as stated in oid4vc_sectrust P-40 (https://openid.github.io/OpenID4VC_SecTrust/draft-oid4vc-security-and-trust.html#name-security-requirement-p-40) an attacker might share a QR code or a link to a victim that would authenticate for him.
The issue is said to be mitigated via the browser API (https://digitalcredentials.dev/docs/wallets/android/#the-provider-api) giving the ability to link a user session to a nonce in case of same-device but also with cross-device by enabling the different devices to communicate one with the other. (@jogu tell me if I am correct on this)
An other way to mitigate the issue would be to provide a short time to live for QR codes and links using the resource created for handling direct_post requests. During the direct_post requests the verifier would be enforced to check the validity of the request by verifying the expiration set on the before step creating the QR code or the link.
The solution would help in both ways, using browser API or not, preventing the authorization request share by setting a short expiration to the direct_post request associated with the verifiable credential demand.
There is a working version of verifier enabling this with little updates, here is the associated commit https://github.com/malach-it/boruta_auth/commit/a104d2e5f77e646d8338884669df88b2648abecf
Unfortunately, short-lived codes/URLs is an insufficient mitigation that can easily be circumvented by simple adaptations by the attacker. For example, an attacker might provide a static QR code to his website were then a redirect to a fresh auth request URL is performed. Or the QR code can be updated on a website.
For now, it is the only one I see since even using browser API the devices have to be interconnected somehow (Bluetooth or other means) which is not the case for most of the holders' setups.
Would you see other ways to mitigate this?
EDIT
In the case you state, the holder would authenticate for himself, the attacker can only trigger a casual authentication keeping holder privacy
I don't know exactly how the browser API will handle this, but ideally, no persistent connection between the devices is needed - just a proof that they are in proximity.
In the same-device flow, the problem can be mitigated with existing protocol features (essentially checking that the nonce matches the session that was started in the browser) as described here.
For the cross-device flow, I don't see any mitigation other than OS/browser support for a secure cross-device transfer that includes an origin check.
Do you know how current cross-device implementations solve the issue?
As stated in the recommandations there are several ways to prevent session fixations, proximity being the best solution but also one with the higher costs. Would there be more cost effective solutions? Balancing practical security and pragmatism.
For now, it is the only one I see since even using browser API the devices have to be interconnected somehow (Bluetooth or other means) which is not the case for most of the holders' setups.
In the current Chrome implementation, a qr code is used to establish an ephemeral bluetooth connection which then establishes a TCP connection via a relay server. There is no need to pre-establish bluetooth connections nor is the user really aware of bluetooth being used - using the FIDO CTAP hybrid protocol - this works regardless of the OS on either end and the user doesn't have to be logged in to the same account on desktop and mobile for it to work. It works for the majority of holders.
It works exactly the same as cross device passkeys, which also use FIDO CTAP hybrid. see e.g. https://youtu.be/SWocv4BhCNg?si=GG-DjXmES90WQqML&t=146
Do you know how current cross-device implementations solve the issue?
They either don't or rely on less-than-ideal user-based solutions ("Only click OK if you got here from a secure page"). They may additionally use a-posteriori detection of such attacks. Having a closed ecosystem helps to reduce the potential impact (looking at banking solutions in the nordics here).
As stated in the recommandations there are several ways to prevent session fixations, proximity being the best solution but also one with the higher costs. Would there be more cost effective solutions? Balancing practical security and pragmatism.
From all that I have seen so far, as soon as your ecosystem is open, proximity is the best one. User-based solutions are the easiest to deploy, but also notoriously insufficient. This should provide a comprehensive list of potential mitigations.
It works exactly the same as cross device passkeys, which also use FIDO CTAP hybrid. see e.g. https://youtu.be/SWocv4BhCNg?si=GG-DjXmES90WQqML&t=146
Note that firefox ESR does not implement the FIDO CTAP hybrid protocol. The demo is impressive.
("Only click OK if you got here from a secure page")
What would be the risk of not coming from a secure page?
From all that I have seen so far, as soon as your ecosystem is open, proximity is the best one. User-based solutions are the easiest to deploy, but also notoriously insufficient.
Let's suppose the link has a lifetime of one minute, the attacker would have one minute to force the holder to open his authorization link by sending it either by email or text message. The victim would have to open and read the fishing message within that minute and be convinced to open the link to present his verifiable credential. Definitely the probability is non-zero but in my sense low enough to enable this kind of solution.
Have you examples of working solutions enabling the proximity in open ecosystems? It might help to have such insights.
("Only click OK if you got here from a secure page")
What would be the risk of not coming from a secure page?
It may be a phishing website. (Not that we should expect anyone to reliable judge whether a website is a phishing website or not.)
From all that I have seen so far, as soon as your ecosystem is open, proximity is the best one. User-based solutions are the easiest to deploy, but also notoriously insufficient.
Let's suppose the link has a lifetime of one minute, the attacker would have one minute to force the holder to open his authorization link by sending it either by email or text message. The victim would have to open and read the fishing message within that minute and be convinced to open the link to present his verifiable credential. Definitely the probability is non-zero but in my sense low enough to enable this kind of solution.
Suppose the link generated by the verifier is https://example.com/auth?nonce=<changes_every_minute>&other_stuff=.... The attacker would not send this link in the QR code or phishing email, but instead just https://example.com/auth?id=xyz and as soon as a visitor comes to that link, generate a new link from the "real" verifier and redirect the user there.
I would not say to change the nonce every minute but to have an expiration to the code used to reference the direct post request.
The attack you reference would trigger an authentication to the verifier, the holder would keep his identity information private to the verifier relying party which would not be a leak. I do not see issues here.
The attack you reference would trigger an authentication to the verifier, the holder would keep his identity information private to the verifier relying party which would not be a leak. I do not see issues here.
The problem is when the holder's information gets into an attacker controller session at the verifier. That is a leak.
As I understand, the origin of the authentication is the holder browser, then the trust relationship between the holder and the verifier is not broken. There is no way the attacker can access identity information but a demand to the verifier which should be trusted.
the origin of the authentication is the holder browser
No, in the attack the origin of the authentication (I think you mean "the session at the verifier where the authentication was started"?) is the attacker's browser.
Each browser has its session, if the attacker redirects the victim to the authorize URL, the session would be the one of the holder.
On an other hand, the attacker can start the flow and enforce the victim to navigate to the response location of the attacker authorize request which I would mitigate by enabling this location to expire.
Is it possible for the browser API to be compatible with not up-to-date mobiles? Is the link between the desktop browser and the mobile possible in all use cases (thinking about cross environments)?
It would be beneficial to include the following in the QR code:
- A nonce
- An expiration time (exp)
The Relying Party (RP) should bind the user-agent with the issued QR code in such a way that a scam attack would not succeed unless the adversary knows and configures their user-agent with the same data as the victim's user-agent.
Edited: my comment is related to cross device only.
@patatoid
Each browser has its session, if the attacker redirects the victim to the authorize URL, the session would be the one of the holder.
If the binding of the nonce to the session is properly checked in same-device flows, this mitigates the attack.
For cross-device flows, however, where the response is processed in a browser different than the one where the request was started, this mitigation cannot be applied. This is where the proximity check can help.
On an other hand, the attacker can start the flow and enforce the victim to navigate to the response location of the attacker authorize request which I would mitigate by enabling this location to expire.
As above, expiration doesn't help, as the attack can be executed immediately after acquiring the authorization request. There is no need to replay a QR code or link that contains any elements that expire. (Also @peppelinux)
As above, expiration doesn't help, as the attack can be executed immediately after acquiring the authorization request. There is no need to replay a QR code or link that contains any elements that expire. (Also @peppelinux)
I was discussing a scam attack. Below is an example of mitigation using a nonce within the QR code, where Alice is the attacker and Bob is the victim.
- Alice initiates a fraud campaign and calls Bob, offering a special discount for items from a specific Relying Party (RP).
- Alice accesses the RP's authentication page and obtains the QR code. The RP uses a nonce and expiration time (exp) and binds Alice's user-agent to the nonce issued within the QR code.
- Alice sends the QR code to Bob.
- Bob scans the QR code to authenticate.
- The RP detects a mismatch in the user-agent and, due to this inconsistency, refuses to proceed. Bob receives an error message and apologizes to Alice.
- Alice realizes that the RP cannot be exploited for the fraud campaign.
The expiration time (exp) mitigates multiple attempts to configure the user-agent, where the attacker tries to guess the user-agent configuration to match Bob's.
This mitigation has two weaknesses:
- Alice might ask Bob to connect to a website under her control to inspect Bob's user-agent configuration.
- Users with automatic random user-agent configurations would not be able to use these types of QR codes bound to the user-agent configuration.
I was discussing a scam attack. Below is an example of mitigation using a nonce within the QR code, where Alice is the attacker and Bob is the victim.
- Alice initiates a fraud campaign and calls Bob, offering a special discount for items from a specific Relying Party (RP).
- Alice accesses the RP's authentication page and obtains the QR code. The RP uses a nonce and expiration time (exp) and binds Alice's user-agent to the nonce issued within the QR code.
- Alice sends the QR code to Bob.
- Bob scans the QR code to authenticate.
- The RP detects a mismatch in the user-agent and, due to this inconsistency, refuses to proceed. Bob receives an error message and apologizes to Alice.
- Alice realizes that the RP cannot be exploited for the fraud campaign.
I don't understand how this works. The whole problem with the cross device flow is that there's multiple devices involved (and hence multiple browsers involved, if there is a redirect back to the RP) even in the case where there isn't an attacker.
Note that firefox ESR does not implement the FIDO CTAP hybrid protocol.
CTAP is typically implemented in platforms, not user agents (though there are some exceptions). Firefox supports CDA on both Windows and macOS via the platform.
Also, just to be super clear, the QR code for FIDO Cross-Device Authentication is optional, and does not contain any information about the actual WebAuthn or Digital Credential request. It is solely for establishing a secure relationship between the two devices. This is one of the reasons FIDO CDA + Digital Credentials API is the preferred method for digital presentation of a VDC.
While not strictly a part of the protocol, a possible mitigation for cross-device phishing attacks is to ask the user to confirm details after the wallet has provided the credentials to the verifier using the redirect_uri.
- Alice initiates a phishing campaign and gets Bob to visit
attacker.comon Computer showing a proxied authentication page for the Relying Party (RP) `example.com. - Bob scans the QR code with Mobile to authenticate.
- Bob completes the authentication / consent in the Wallet and the result is sent to the RP using
direct_post - The Wallet redirects Bob on Mobile to the redirect_uri provided by RP.
- RP asks Bob to confirm that the website they are authenticating to on Computer has
example.comfor the domain. It could also show other information, such as IP address, which would help Bob identify if the website they are on is legitimate. - Bob realizes that the website on Computer is
attacker.comand notexample.comso on Mobile rejects the RP's confirmation. - Alice never receives a successful authentication as the RP was not given confirmation by Bob.
This method is not perfect as it relies on the user successfully assessing the information provided, but it provides an extra layer of security in situations where the user controls both devices.
I think this technically works, it's one of the mitigations mentioned in the cross device BCP, but it's known to be a mitigation that doesn't really work in practice with the majority of users.
Apologizes for the revival of the issue.
The solution I suggest is more a practice than a formal definition we can add to the specification since it is only a mitigation. There may be other ways to mitigate the issue, I would not know where to gather this kind of knowledge.
The solution I suggest is more a practice than a formal definition we can add to the specification since it is only a mitigation.
the best we can do is to add text to https://openid.github.io/OpenID4VP/openid-4-verifiable-presentations-wg-draft.html#name-security-considerations-3 are there are specific/concrete additions you have in mind?
otherwise, would suggest closing this issue.
please do not do PRs if the issue is not labelled ready for PR.
I think the best thing we could do here is to add DC API to the session fixation session. cc @danielfett
In this post I explain why the DC API is a solution and short-lived QR codes are definitely not a solution: https://danielfett.de/2025/03/10/cross-device-session-fixation/
To continue the discussion we had on the associated PR (#467), the suggested ways of mitigation are the current practices to solve the issue. VC API provide new ways of mitigation using a protocol that requires an OS update.
I think those should be stated in the Session Fixation section helping implementers to be aware of this and suggest ways to solve it.
I would both state the current practices and VC API since it provides more freedom to the implementers for addressing the issue that is definitely to be taken care of.
I am also thinking about protecting authorization link against CSRF attacks. It would require the authorization endpoint to be a POST.
According to me, it would make sense since the authorization bypass authentication, the wallet being recognized cryptographically. Does it makes sense?
Taking an other angle, the holder can perform a SIOPV2 in order for the verifier to fetch the client_id corresponding to the did provided and proved by the given id_token. That client_id can then be verified at presentation, securing the flow. Does it make more sense?
I am also thinking about protecting authorization link against CSRF attacks. It would require the authorization endpoint to be a POST.
I don't see how the authorization endpoint call can be made a POST. That definitely won't work in a QR Code, nor does it work for deep links on a mobile OS.
Closed in favor of #620