-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Security consideration: user consent before payment #365
Conversation
index.html
Outdated
window and the user has an opportunity to confirm a transaction via a | ||
button. But if the payment handler does not open a window, or opens a | ||
window without an opportunity for user interaction, the browser might | ||
prompt the user to confirm the payment handler's behavior before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or opens a window without an opportunity for user interaction,
How would the payment sheet/browser know if the payment handler didn't provide a button?
I think we need to force a "payment confirmed" event somehow, which must be triggered explicitly by user activation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I look forward to hearing from @romandev, @rsolomakhin, and @danyao on that idea. If we adopt something like that, then this text would become something like "The reason we have that event is to prevent the scenario where...".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can add a finalizeResponse()
method to PaymentRequestEvent
that the payment handler must call with a user activation. I worry about this being brittle for scenarios like this:
- User interaction happens inside a cross-origin iframe in the PH window, so there's no way to transfer that user activation to the PH origin to trigger
PaymentRequestEvent.finalizeResponse()
. This can be the case if the PH embeds a 3DS flow from a bank or PSP. - Browser minimal UI flow where the browser shows a native UI for a PH without showing any web content from the PH.
The alternative I had in mind was for the browser to track user interactions within the payment handler's web content as an internal state, e.g. [[userInteracted]]
of the PaymentRequest. I need to dig more into the code to know how hard this would be. The main downside is that we're leaving the definition of "user interaction" to the browser instead of leveraging the standardized "user activation" definition, so be a source of interop subtleties. The upside is that "user activation" as spec'ed today has very complex rules for how they can be transferred. Opening it up to address the iframe case could actually increase the overall security surface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HI @danyao,
The use cases you cited are very helpful.
If it is up to the payment handler to call PaymentRequestEvent.finalizeResponse(),
that seems to leave open the possibility that the payment handler could lie.
I was thinking more along these lines:
- In a payment handler window, the browser keeps track of all user interaction events, whether at the top level or in descendant iframes.
- If the number of user events logged before show() == 0 then prompt the user.
I am not a browser maker, so I don't know whether that makes sense.
Regarding the minimal UI use case, that seems like one where the browser could enforce the user interaction requirement itself rather than relying on the content-less PH to do so.
Ian
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is up to the payment handler to call PaymentRequestEvent.finalizeResponse(),
that seems to leave open the possibility that the payment handler could lie.
Payment handler can't lie if the browser rejects the show promise if PaymentRequestEvent.finalizeResponse()
is called without a user activation.
Thinking about it a bit more, the iframe use case I described can fit in today's user activation model [1] because click events are allowed to propagate upwards to parent frames, even cross-origin ones. This is good.
For the minimal UI case, we can still ask payment handler to call finalizeResponse()
, but browser can override the user activation requirement based on user's interaction with the native UI.
The other question is backward compatibility: how should a browser handle legacy payment handlers that don't yet call finalizeResponse()
explicitly? Maybe we can take a two-step approach:
- Bridge solution: browser tracks user activation inside PH window and implicitly call
finalizeResponse()
when the window closes. - End state: PH has to explicitly call
finalizeResponse()
.
We would also need an extra state to PaymentRequest
to track if an implementation specific window is ever opened. If not, the show promise should reject when the PH attempts to resolve the promise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may be missing something because I haven't looked deeply into this recently.
If I am missing something, please correct me.
I think @danyao 's suggestion is reasonable overall, and I support her opinion.
BTW, This may be a silly question but I'm still missing something. What's the subtle difference between new finalizeResponse()
and existing respondWith()
?
In my understanding and according to the spec text, respondWith()
already checks whether the PaymentRequestEvent.isTrusted
is true
and doesn't it mean that respondWith()
is only allowed by user activation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @romandev - The PaymentRequestEvent.isTrusted
check in respondWith()
ensures that request.show()
is triggered with a user gesture. I think to protect the user from the [one-click collection of detailed user information without UI][1] privacy attack, I think browsers should also require that the user has interacted with the payment handler UI before allowing the showPromise
to resolve. Do you think this makes sense?
finalizeResponse()
is just a strawman. 😅 I need to study respondWith()
a bit more to see if we truly needs a second method. My initial intuition is based on code examples that show a payment handler calling respondWith()
immediate in the paymentrequest
event handler to return a Promise. If we want to use respondWith()
to capture the requirement that the user has interacted with the payment handler's web content, then it probably needs to be called outside of the event handler and as part of a click event handler on the payment handler's web content. I'm not too sure yet how this click event handler can transfer to the service worker...
All that said, I don't think we need to figure this all out before updating the non-normative note here. WDYT @ianbjacobs @marcoscaceres @romandev ? We can tackle the actual design in a separate issue.
[1] https://w3c.github.io/webpayments/proposals/privacy-threat-model.html#one-click-no-ui
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi all,
- Updated (and simplified) the pull request based on @danyao's suggestion.
- Created new issue for design: Require user interaction before payment handler response returned #369
Let me know if you're ok to merge the security consideration in the meantime.
Thanks!
Ian
index.html
Outdated
window and the user has an opportunity to confirm a transaction via a | ||
button. But if the payment handler does not open a window, or opens a | ||
window without an opportunity for user interaction, the browser might | ||
prompt the user to confirm the payment handler's behavior before |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example, a user agent might do nothing if a payment handler opens a
window and the user has an opportunity to confirm a transaction via a
button. But if the payment handler does not open a window, or opens a
window without an opportunity for user interaction, the browser might
prompt the user to confirm the payment handler's behavior before
This seems too prescriptive. Would it be sufficient to say something like this?
"...At the same time, user agents should take necessary steps to make sure the user is made aware when a payment request is invoked, and has an opportunity to interact with the payment handler before the merchant is allowed to receive the payment response from the payment handler."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
in line with:
https://github.com/w3c/payment-handler/wiki/2020-Mar-proposed-changes#mandatory-user-interaction-with-payment-handler-window
Implementation commitment:
Preview | Diff