OID4VP - Protecting response mode post

Issue #1717 resolved
David W Chadwick created an issue

The current text says

When HTTP "POST" method is used to send VP Token, there is no session for the Verifier to validate whether the Response is sent by the same Wallet that has received the Authorization Request. It is RECOMMENDED for the Verifiers to implement mechanisms to strengthen such binding.

This issue has been created to allow us to discuss possible mechanisms for strengthening this binding so that we can add some guidelines to our specification.

Here is the first proposal. The redirect URL that is sent from the RP to the AS is a dynamic URL containing a secret such as https://example.com/secret=32bit-OTP. The AS should post the response to this URL and the RP should keep a record of the OTPs it has sent so that it can reject any incoming calls that do not quote an outstanding OTP, and each OTP should only be used once.

Comments (15)

  1. Torsten Lodderstedt

    You can encode a dynamic secret in the URL, however there is already the nonce (somewhere buried in the VP) you can use to make that connection. I think the text is misleading as it wants to point out that the verifier does not have a user device context since the request is directly received in the backend whereas in redirect based flows, the verifier also has access to its own state (cookies, local storage).

  2. Joseph Heenan

    I think one of the goals here should probably be to try and avoid sending a credential to an RP that hadn’t actually requested it. nonce isn’t great for that as I think it’s in the front channel redirect so isn’t really a ‘secret’, and the RP has already received the credential by the time it and check nonce, and general implementation experience has been that the AS/wallet are more into protecting the user and actually implementing checks in the protocol than RPs are (hence why OAuth went with PKCE [which can mostly be enforced by AS] rather than a nonce mechanism [which can only be enforced by RP]).

    One idea would be to do some kind of challenge-response POST to the redirect url. Something like:

    1. AS POSTs to redirect url with PKCE challenge, RP responses with code challenge in response body.
    2. If code challenge is correct, AS POSTs again to the redirect url, this time with the credential(s) included.

    (and as David suggests, RPs can reject requests with an unrecognised PKCE challenge, and could enforce that each challenge is only used once)

  3. David W Chadwick reporter

    We are currently implementing administrative trust in RPs as described in issue #1551. So if this is implemented it takes care of protecting the user from the RP, as the wallet will not send the user’s PII/VCs to an untrustworthy RP (unless the user overrides the trust infrastructure and says go ahead anyway - rather like browsers do when they go to a web site with a faulty TLS PKC). So this issue should concentrate on protecting the RP from receiving unsolicited POSTs to its URL. In this case the PKCE challenge/response is not needed as it is not protecting the RP from receiving unsolicited messages any more than a secret URL is.

  4. David W Chadwick reporter

    We have the following suggestion to make, based on our internal implementation discussions. As Torsten points out, there is a nonce (random number) provided by the RP to the wallet and the wallet puts this random number into the VP. So the RP will know if the VP is destined for itself. However this does not stop a DDOS attack on the RP as the RP will need to read in and parse the response, decrypt the JWT of the VP and get the nonce before it knows if this response is valid or not. This is a lot of processing.

    So our suggestion is that the response is sent to “<redirectURL>?<nonce>” so that the RP can immediately see if the response is expected. If the nonce is one that the RP is waiting for, then it will process the response, but if the nonce is unknown (or has already been used) then the RP will immediately return an error code to the wallet.

    Is this a satisfactory solution?

  5. Joseph Heenan

    Do you definitely mean decrypt there David? Or just decode? (I can’t see a reference to encryption/decryption in the current spec.)

  6. Joseph Heenan

    Thanks David, I understand now.

    So I don’t think it’s necessarily bad to verify the existing nonce before checking the signature, though I can equally see an argument for having the nonce outside to make that clearer.

    When we defined similar semantics in CIBA for the push response ( https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0.html#rfc.section.10.3 ) we got some strong pushback that it’s better to use bearer access tokens (i.e. Authorization: Bearer 8d67dc78-7faa-4d41-aabd-67707b374255 for this purpose as they can then be processed at the API gateway level.

    The main difference between CIBA and the direct post flow is that in the direct post flow any token (whether we call it a nonce or a bearer access token) is passed via the front channel and potentially leaked.

  7. David W Chadwick reporter

    I can definitely see similarities between the CIBA push response and what we are trying to do here for the vp_token pushed response to the RP. It's true that the nonce can be leaked on transfer to the wallet, because in the cross device flow it is in the QR code, and in the same device flow it goes via the browser. But given that this exchange is a simple request-response (and not a series of messages) then it cannot support the equivalent of auth_req_id without a significant change to the protocol.

    However if we make our existing nonce logically equivalent to CIBA’s client_notification_token then the POST can contain the nonce as the bearer authorization token and everything else can stay “as is” (with the nonce being in the VP as before).

    So I suggest that we could resolve this issue by adding text that requires the POST to contain a bearer authz token holding the client’s nonce.

  8. David W Chadwick reporter

    Talking to my develop he suggests that adding the nonce dynamically to the returnURL is a much easier implementation approach than requiring the header to contain a bearer authz token holding the nonce. Do you see any security differences in the two approaches?

  9. Joseph Heenan

    I think that’s more into an interoperability/ease of implementation discussion.

    Whilst in the url is easier for you, there are quite a few (generally larger) organisations that prefer to verify authorization at the API gateway level, which may not be possible/as easy if the token is part of the URL.

  10. David W Chadwick reporter

    Understood. In this case the RP can decide which is best for it. If the RP sends a dynamic URL containing the nonce, then this is what the wallet should use for the POST, but if it is a static URL then the wallet should add the nonce to the authz bearer token in the header.

  11. Kristina Yasuda

    +1 to adding a reference to cross-device BCP. let’s do that after BCP is published as the oauth WG draft

  12. Log in to comment