1. Introduction
This section and its sub-sections are non-normative.
This specification defines an API that enables the use of strong authentication methods in payment flows on the web. It aims to provide the same authentication benefits and user privacy focus as [webauthn-3] with enhancements to meet the needs of payment processing.
Similarly to [webauthn-3] , this specification defines two related processes involving a user. The first is § 3 Registration (formerly "enrollment"), where a relationship is created between the user and the Relying Party . The second is § 4 Authentication , where the user responds to a challenge from the Relying Party (possibly via an intermediary payment service provider) to consent to a specific payment. An important feature of Secure Payment Confirmation is that the merchant (or another entity) may initiate the authentication ceremony on the Relying Party’s behalf.
Functionally,
this
specification
defines
a
new
payment
method
for
the
PaymentRequest
API,
and
adds
a
WebAuthn
Extension
to
extend
[webauthn-3]
with
payment-specific
datastructures
and
to
relax
assumptions
to
allow
the
API
to
be
called
in
payment
contexts.
1.1. Use Cases
Although [webauthn-3] provides general authentication capabilities for the Web, the following use cases illustrate the value of the payment-specific extension defined in this specification.
We presume that the general use case of cryptographic-based authentication for online transactions is well established.
Note: These sections are still a WIP.
1.1.1. Cryptographic evidence of transaction confirmation
In many online payment systems, it is common for the entity (e.g., bank) that issues a payment instrument to seek to reduce fraud through authentication. [webauthn-3] and this specification make it possible to use authenticators to cryptographically sign important payment-specific information such as the origin of the merchant and the transaction amount and currency. The bank, as the Relying Party , can then verify the signed payment-specific information as part of the decision to authorize the payment.
If
the
bank
uses
plain
[webauthn-3]
,
the
payment-specific
information
to
be
verified
must
be
stored
in
the
WebAuthn
challenge
.
This
raises
several
issues:
-
It is a misuse of the
challenge
field (which is intended to defeat replay attacks). -
There is no specification for this, so each bank is likely to have to devise its own format for how payment-specific information should be formatted and encoded in the challenge, complicating deployment and increasing fragmentation.
-
Regulations may require evidence that the user was shown and agreed to the payment-specific information. Plain [webauthn-3] does not provide for this display: there is no specified UX associated with information stored in the
challenge
field.
These limitations motivate the following Secure Payment Confirmation behaviors:
-
The
challenge
field is only used to defeat replay attacks, as with plain [webauthn-3] . -
SPC specifies a format for payment-specific information. This will enable development of generic verification code and test suites.
-
SPC guarantees that the user agent has presented the payment-specific information to the user in a way that a malicious website (or maliciously introduced JavaScript code on a trusted website) cannot bypass.
-
The payment-specific information is included in the
CollectedClientData
dictionary, which cannot be tampered with via JavaScript.
NOTE: Banks and other stakeholders in the payments ecosystem trust payments via browsers sufficiently today using TLS, iframes, and other Web features. The current specification is designed to increase the security and usability of Web payments.
-
1.1.2. Registration in a third-party iframe
If a bank wishes to use [webauthn-3] as the Relying Party , that specification requires the bank to register the user in a first party context. Registration can happen outside of a transaction while the user is visiting the bank’s site. It is also useful to be able to register the user during a transaction, but any registration that interrupts the payment journey creates a risk of transaction abandonment.
This limitation motivates the following Secure Payment Confirmation behavior:
-
SPC supports cross-origin registration from an iframe in a third-party context. For instance, this registration might take place following some other identity and verification ( ID&V ) flow (e.g., SMS OTP).
1.1.3. Merchant control of authentication
Merchants seek to avoid user drop-off during checkout, in particular by reducing authentication friction. A Relying Party (e.g., a bank) that wishes to use [webauthn-3] to authenticate the user typically does so from an iframe. However, merchants would prefer to manage the user experience of authenticating the user while still enabling the Relying Party to verify the results of authentication.
This limitation motivates the following Secure Payment Confirmation behavior:
-
With SPC, other parties than the Relying Party can use authentication credentials on behalf of the Relying Party. The Relying Party can then verify the authentication results.
An additional benefit of this feature to Relying Parties is that they no longer need to build their own front-end experiences for authentication. Instead, payment service providers are likely to build them on behalf of merchants.
NOTE: Relying Parties that wish to provide the authentication user experience may still do so using SPC from an iframe.
1.2. Sample API Usage Scenarios
In this section, we walk through some scenarios for Secure Payment Confirmation and the corresponding sample code for using this API. Note that these are example flows and do not limit the scope of how the API can be used.
1.2.1. Registration
This is the first-time flow, in which a new credential is created and stored by an issuing bank.
-
The user visits
merchant.com
, selects an item to purchase, and proceeds to the checkout flow. They enter their payment instrument details, and indicate that they wish to pay (e.g., by pressing a "Pay" button). -
The merchant communicates out-of-band (e.g., using another protocol) with the bank that issued the payment instrument. The issuing bank requests verification of the user, and provides a bank-controlled URL for the merchant to open in an iframe.
-
The merchant opens an iframe to
bank.com
, with theallow
attribute set to " payment ". -
In the iframe, the issuing bank confirms the user’s identity via a traditional means (e.g., SMS OTP). After confirmation, the bank invites the user to register in SPC authentication for future payments.
-
The user consents (e.g., by clicking an "Register" button in the bank UX), and the bank runs code in the iframe (see example below).
-
The user goes through a WebAuthn registration flow. A new credential is created and returned to the issuing bank who stores it in their server-side database associated with the user and payment instrument(s).
-
The verification completes; the bank iframe closes and the merchant finishes the checkout process for the user.
The sample code for registering the user follows:
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } const publicKey= { // The challenge should be created by the bank server and sent to the iframe. challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the server */ ]), // Relying Party: rp: { name: "Fancy Bank" , }, // User: user: { // An id that the bank server can use to identify this user in future interactions. id: Uint8Array. from( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "jane.doe@example.com" , displayName: "Jane Doe" , }, // This Relying Party will accept either an ES256 or RS256 credential, but // prefers an ES256 credential. pubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" }, { type: "public-key" , alg: - 257 // "RS256" } ], // This Relying Party requires user verification. authenticatorSelection: { userVerification: "required" , residentKey: "required" , authenticatorAttachment: "platform" , }, timeout: 360000 , // 6 minutes // Indicate that this is an SPC credential. This is currently required to // allow credential creation in an iframe, and so that the browser knows this // credential relates to SPC. // // It is expected that a future version of the spec may remove the need for // this extension. extensions: { "payment" : { isPayment: true , } } }; // Note: The following call will cause the authenticator to display UI. navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // Send new credential info to server for verification and registration. }). catch ( function ( err) { // No acceptable authenticator or user refused consent. Handle appropriately. });
1.2.2. Authentication
This is the flow when a user with an already registered credential is performing a transaction and the issuing bank and merchant wish to use Secure Payment Confirmation.
-
The user visits
merchant.com
, selects an item to purchase, and proceeds to the checkout flow. They enter their payment instrument details, and indicate that they wish to pay (e.g., by pressing a "Pay" button).Note: The cross-origin use of SPC credentials makes it possible for the user to "register once" and authenticate on any merchant origin, not just the merchant origin where the user first registered for SPC.
-
The merchant communicates out-of-band with the issuing bank of the payment instrument (e.g., using another protocol). The issuing bank requests verification of the user, and at the same time informs the merchant that it accepts SPC by providing the information necessary to use the API. This information includes a challenge and any credential IDs associated with this user and payment instrument(s).
-
The merchant runs the example code shown below.
-
The user agrees to the payment-specific information displayed in the SPC UX, and performs a subsequent WebAuthn authentication ceremony. The signed cryptogram is returned to the merchant.
-
The merchant communicates the signed cryptogram to the issuing bank out-of-band. The issuing bank verifies the cryptogram, and knows that the user is valid, what payment-specific information has been displayed, and that the user has consented to the transaction. The issuing bank authorizes the transaction and the merchant finishes the checkout process for the user.
The sample code for authenticating the user follows. Note that the example code presumes access to await/async, for easier to read promise handling.
if ( ! window. PaymentRequest) { /* PaymentRequest not available; merchant should fallback to traditional flows */ } const request= new PaymentRequest([{ supportedMethods: "secure-payment-confirmation" , data: { // List of credential IDs obtained from the bank. credentialIds, // The challenge is also obtained from the bank. challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the bank */ ]), instrument: { displayName: "Fancy Card ****1234" , icon: "https://fancybank.com/card-art.png" , }, payeeOrigin: "https://merchant.com" , timeout: 360000 , // 6 minutes }], { total: { label: "Total" , amount: { currency: "USD" , value: "5.00" , }, }, }); try { const canMakePayment= await request. canMakePayment(); if ( ! canMakePayment) { throw new Error( 'Cannot make payment' ); } const response= await request. show(); await response. complete( 'success' ); // response.data is a PublicKeyCredential, with a clientDataJSON that // contains the transaction data for verification by the issuing bank. /* send response.data to the issuing bank for verification */ } catch ( err) { /* SPC cannot be used; merchant should fallback to traditional flows */ }
2. Dependencies
This specification relies on several other underlying specifications, listed below and in Terms defined by reference .
- WebAuthn Conditional UI
-
Secure Payment Confirmation only shows the transaction UX if one of the passed credentials is valid for the current device, without requiring a user interaction. This concept is not currently part of [webauthn-3] , but is on the roadmap for a future enhancement.
Until this is available, user agents can consider either storing a local cache of WebAuthn credentials created for this device, or always showing the transaction UX even if the user may be unable to complete the authentication.
TODO : Bikeshed the name.NOTE: To quickly support an initial SPC experiment, this API was designed atop existing implementations of the Payment Request and Payment Handler APIs. There is now general agreement to explore a design of SPC independent of Payment Request. We therefore expect (without a concrete timeline) that SPC will move away from its Payment Request origins. For developers, this should improve feature detection, invocation, and other aspects of the API.
3. Registration
To
register
a
user
for
Secure
Payment
Confirmation,
relying
parties
should
call
navigator.credentials.create()
,
with
the
payment
WebAuthn
Extension
specified.
Note: In this specification we define an extension in order to allow (1) credential creation in a cross-origin iframe (which WebAuthn does not yet allow) and (2) the browser to cache SPC credentials in the absence of WebAuthn Conditional UI . If these capabilities are available in future versions of WebAuthn, we may remove the requirement for the extension from SPC. Note that SPC credentials (with the extension) are otherwise full-fledged WebAuthn credentials. This specification does not preclude their use in other use-cases (e.g., login).
4. Authentication
To authenticate a payment via Secure Payment Confirmation, this specification defines a new payment method , " secure-payment-confirmation ". This payment method confirms the transaction with the user and then performs an authentication ceremony to authenticate the user and create a signed blob representing the authentication ceremony.
At a high level, authentication for Secure Payment Confirmation is similar to [webauthn-3] , with one major conceptual shift. Secure Payment Confirmation allows a third-party (e.g., the merchant) to trigger an authentication ceremony on behalf of the Relying Party , passing in credentials that it has obtained from the Relying Party on some other unspecified channel. See § 1.1.3 Merchant control of authentication .
4.1. Payment Method: Secure Payment Confirmation
This specification defines a new payment handler , the Secure Payment Confirmation payment handler , which handles requests to authenticate a given payment.
PaymentRequest’s
constructor
somehow,
to
enforce
that
when
"
secure-payment-confirmation
"
is
used,
exactly
one
method
is
given.
4.1.1. Payment Method Identifier
The standardized payment method identifier for the Secure Payment Confirmation payment handler is " secure-payment-confirmation ".
4.1.2. Monkey-patch to [payment-method-id]
Add the following to the registry of standardized payment methods in [payment-method-id] :
- " secure-payment-confirmation "
-
The Secure Payment Confirmation specification.
4.1.3.
SecurePaymentConfirmationRequest
Dictionary
dictionary SecurePaymentConfirmationRequest {; ;required BufferSource challenge ;required FrozenArray <BufferSource >credentialIds ;required PaymentCredentialInstrument instrument ;; ;unsigned long timeout ;required USVString payeeOrigin ;AuthenticationExtensionsClientInputs extensions ; };
The
SecurePaymentConfirmationRequest
dictionary
contains
the
following
members:
-
challenge
member, of type BufferSource -
A random challenge that the relying party generates on the server side to prevent replay attacks.
-
credentialIds
member, of type FrozenArray< BufferSource > -
The list of credential identifiers for the given instrument.
-
instrument
member, of type PaymentCredentialInstrument -
The description of the instrument name and icon to display during registration and to be signed along with the transaction details.
-
timeout
member, of type unsigned long -
The number of milliseconds before the request to sign the transaction details times out. At most 1 hour.
-
payeeOrigin
member, of type USVString -
The fully qualified origin of the payee that this SPC call is for (e.g., the merchant).
-
extensions
member, of type AuthenticationExtensionsClientInputs -
Any WebAuthn extensions that should be used for the passed credential(s). The caller does not need to specify the payment extension ; it is added automatically.
4.1.4. Steps to check if a payment can be made
The
steps
to
check
if
a
payment
can
be
made
for
this
payment
method,
for
an
input
SecurePaymentConfirmationRequest
request
,
are:
-
If request .
credentialIds
is empty, returnfalse
. -
If request .
payeeOrigin
is not a fully qualified origin , returnfalse
. -
If request .
instrument
.displayName
is empty, returnfalse
. -
Fetch the image resource for the icon, passing «["
src
" → request .instrument
.icon
]» for image . If this fails, returnfalse
.Note: The image resource must be fetched whether or not any credential matches, to defeat attempts to probe for credential existence .
-
Optionally, the user agent may elect to return
false
. If a user agent does so, it must take care to maintain authentication ceremony privacy , e.g., by presenting an alternative UI to the user such that the website cannot detect the difference between no-matching credentials and the user declining to authenticate. -
Return
true
.
4.1.5. Displaying a transaction confirmation UX
To
avoid
restricting
User
Agent
implementation
choice,
this
specification
does
not
require
a
User
Agent
to
display
a
particular
user
interface
when
PaymentRequest.show()
is
called
and
the
Secure
Payment
Confirmation
payment
handler
is
selected.
However,
so
that
a
Relying
Party
can
trust
the
information
included
in
CollectedClientPaymentData
,
the
User
Agent
MUST
ensure
that
the
following
is
communicated
to
the
user:
-
The
payeeOrigin
. -
The
total
, that is thecurrency
andvalue
of the transaction. -
The
instrument
details, that is the payment instrumentdisplayName
andicon
.
4.1.6. Steps to respond to a payment request
The
steps
to
respond
to
a
payment
request
for
this
payment
method,
for
a
given
PaymentRequest
request
and
SecurePaymentConfirmationRequest
data
,
are:
-
Let topOrigin be the origin of the top-level frame.
TODO : Specify this concretely -
Let payment be a new a
AuthenticationExtensionsPaymentInputs
dictionary, whose fields are:-
isPayment
-
The boolean value
true
. -
rp
-
TODO
-
topOrigin
-
topOrigin
-
payeeOrigin
-
data .
payeeOrigin
-
total
-
request . [[details]] .
total
-
instrument
-
data .
instrument
TODO : We do not have the rp id at this step; maybe that should just go in the extension processing steps? -
-
Let extensions be a new
AuthenticationExtensionsClientInputs
dictionary whosepayment
member is set to payment , and whose other members are set from data .extensions
. -
Let publicKeyOpts be a new
PublicKeyCredentialRequestOptions
dictionary, whose fields are:-
challenge
-
data .
challenge
-
timeout
-
data .
timeout
-
userVerification
-
extensions
-
extensions
Note: This algorithm hard-codes "required" as the value for
userVerification
, because that is what Chrome’s initial implementation supports. The current limitations may change. The Working Group invites implementers to share use cases that would benefit from support for other values (e.g., "preferred" or "discouraged"). -
-
For each id in
data.credentialIds
:-
Let descriptor be a new
PublicKeyCredentialDescriptor
dictionary, whose fields are:-
type
-
id
-
id
-
transports
-
A sequence of length 1 whose only member is
internal
.
-
-
Append descriptor to publicKeyOpts .
allowCredentials
.
-
-
Let outputCredential be the result of running the algorithm to Request a Credential , passing «["
publicKey
" → publicKeyOpts ]».Note: This triggers [webauthn-3] 's Get behavior
-
Return outputCredential .
5.
WebAuthn
Extension
-
"
payment
"
This client registration extension and authentication extension indicates that a credential is either being created for or used for Secure Payment Confirmation, respectively.
For registration, this extension relaxes the WebAuthn requirements to allow credential creation in a cross-origin iframe, and also allows the browser to identify and cache Secure Payment Confirmation credentials. For authentication, this extension allows a third-party to perform an authentication ceremony on behalf of the Relying Party , and also adds transaction information to the signed cryptogram.
Notably,
a
website
should
not
call
navigator.credentials.get()
with
this
extension
directly;
for
authentication
the
extension
can
only
be
accessed
via
PaymentRequest
with
a
"
secure-payment-confirmation
"
payment
method.
- Extension identifier
-
payment
- Operation applicability
- Client extension input
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsPaymentInputs
; };payment dictionary
{AuthenticationExtensionsPaymentInputs ;boolean isPayment ; // Only used for authentication.; ; ;USVString rp ;USVString topOrigin ;USVString payeeOrigin ;PaymentCurrencyAmount total ;PaymentCredentialInstrument instrument ; };-
isPayment
member, of type boolean -
Indicates that the extension is active.
TODO : Find a better way to do this. Needed currently because other members are auth-time only. -
rp
member, of type USVString -
The Relying Party id of the credential(s) being used. Only valid at authentication time.
-
topOrigin
member, of type USVString -
The origin of the top-level frame. Only valid at authentication time.
-
payeeOrigin
member, of type USVString -
The payee origin that was displayed to the user. Only valid at authentication time.
-
total
member, of type PaymentCurrencyAmount -
The transaction amount that was displayed to the user. Only valid at authentication time.
-
instrument
member, of type PaymentCredentialInstrument -
The instrument details that were displayed to the user. Only valid at authentication time.
-
- Client extension processing ( registration )
-
Note: Reading [webauthn-3] literally, these steps don’t work; extensions are injected at step 12 of
[[Create]]
and cannot really modify anything. However other extensions ignore that entirely and assume they can modify any part of any WebAuthn algorithm!When creating a new credential :
-
Remove the check for sameOriginWithAncestors in step 2.
Note: This allows for creating SPC credentials in a cross-origin iframe, as long as the correct permission policy is set (see § 7 Permissions Policy integration ). We could additionally require and consume a transient activation here, if we felt the permission policy is not sufficient.
-
After step 3, insert the following step:
-
If any of the following are true:
-
options .
authenticatorSelection
.authenticatorAttachment
is not "platform
". -
options .
authenticatorSelection
.residentKey
is not "required
". -
options .
authenticatorSelection
.userVerification
is not "required
".
then throw a
TypeError
.Note: These values are hard-coded as that is what Chrome’s initial implementation supports. The current limitations may change. The Working Group invites implementers to share use cases that would benefit from support for other values.
-
-
-
- Client extension processing ( authentication )
-
When making an assertion with a
AuthenticationExtensionsPaymentInputs
extension_inputs :-
If not in a " secure-payment-confirmation " payment handler, return a "
NotAllowedError
"DOMException
.Note: This guards against websites trying to access the extended powers of SPC without going through the transaction UX .
-
During
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
:-
Skip step 6.1, which compares options.rpId to effectiveDomain
Note: This enables cross-domain authentication ceremonies; see § 1.1.3 Merchant control of authentication .
-
In step 9, instead of creating a
CollectedClientData
, instead create aCollectedClientPaymentData
with:-
type
set to "payment.get
" -
payment
set to a newCollectedClientAdditionalPaymentData
whose fields are:-
rp
-
extension_inputs .
rp
-
topOrigin
-
extension_inputs .
topOrigin
-
payeeOrigin
-
extension_inputs .
payeeOrigin
-
total
-
extension_inputs .
total
-
instrument
-
extension_inputs .
instrument
-
-
All other fields set as per the original step 9.
-
-
-
- Client extension output
-
None
- Authenticator extension processing
-
None
5.1.
CollectedClientPaymentData
Dictionary
dictionary CollectedClientPaymentData :CollectedClientData {required CollectedClientAdditionalPaymentData payment ; };
The
CollectedClientPaymentData
dictionary
inherits
from
CollectedClientData
.
It
contains
the
following
additional
field:
-
payment
member, of type CollectedClientAdditionalPaymentData -
The additional payment information to sign.
5.2.
CollectedClientAdditionalPaymentData
Dictionary
dictionary CollectedClientAdditionalPaymentData {; ; ;required USVString rp ;required USVString topOrigin ;required USVString payeeOrigin ;required PaymentCurrencyAmount total ;required PaymentCredentialInstrument instrument ; };
The
CollectedClientAdditionalPaymentData
dictionary
contains
the
following
fields:
-
rp
member, of type USVString -
The id of the Relying Party that created the credential.
-
topOrigin
member, of type USVString -
The origin of the top level context that requested to sign the transaction details.
-
payeeOrigin
member, of type USVString -
The origin of the payee that was displayed to the user.
-
total
member, of type PaymentCurrencyAmount -
The
PaymentCurrencyAmount
of the [payment-request]total
field. -
instrument
member, of type PaymentCredentialInstrument -
The instrument information that was displayed to the user.
Note
that
there
is
no
paymentRequestOrigin
field
in
CollectedClientAdditionalPaymentData
,
because
the
origin
of
the
calling
frame
is
already
included
in
CollectedClientData
of
[webauthn-3]
.
6. Common Data Structures
The following data structures are shared between registration and authentication.
6.1.
PaymentCredentialInstrument
Dictionary
dictionary PaymentCredentialInstrument {; ;required DOMString displayName ;required USVString icon ; };
The
PaymentCredentialInstrument
dictionary
contains
the
information
to
be
displayed
to
the
user
and
signed
together
with
the
transaction
details.
It
contains
the
following
members:
-
displayName
member, of type DOMString -
The name of the payment instrument to be displayed to the user.
-
icon
member, of type USVString -
The URL of the icon of the payment instrument.
7. Permissions Policy integration
This specification uses the " payment " policy-identifier string from [payment-request] to control access to both registration and authentication. This extends the WebAuthn Permission Policy .
Note:
Algorithms
specified
in
[CREDENTIAL-MANAGEMENT-1]
perform
the
actual
permissions
policy
evaluation.
This
is
because
such
policy
evaluation
needs
to
occur
when
there
is
access
to
the
current
settings
object
.
The
[[Create]](origin,
options,
sameOriginWithAncestors)
and
[[DiscoverFromExternalSource]](origin,
options,
sameOriginWithAncestors)
internal
methods
do
not
have
such
access
since
they
are
invoked
in
parallel
(by
algorithms
specified
in
[CREDENTIAL-MANAGEMENT-1]
).
8. SPC Relying Party Operations
8.1. Verifying an Authentication Assertion
In order to perform an authentication ceremony for Secure Payment Confirmation, the Relying Party MUST proceed as follows:
-
Let credential be a
PublicKeyCredential
returned from a successful invocation of the Secure Payment Confirmation payment handler by the SPC caller .Note: As SPC is designed to enable merchant control of authentication , the entity that invokes SPC may not be the Relying Party . This first step presumes that the SPC caller has returned a credential obtained via SPC to the Relying Party .
-
Perform steps 3-21 as specified in WebAuthn , with the following changes:
-
In step 5, verify that credential .
id
identifies one of the public key credentials provided to the SPC caller by the Relying Party . -
In step 11, verify that the value of C .
type
is the stringpayment.get
. -
In step 12, verify that the value of C .
challenge
equals the base64url encoding of the challenge provided to the SPC caller by the Relying Party . -
In step 13, verify that the value of C .
origin
matches the origin that the Relying Party expects SPC to have been called from. -
After step 13, insert the following steps:
-
Verify that the value of C .
payment
.rp
matches the Relying Party 's origin. -
Verify that the value of C .
payment
.topOrigin
matches the top-level origin that the Relying Party expects. -
Verify that the value of C .
payment
.payeeOrigin
matches the origin of the payee that should have been displayed to the user. -
Verify that the value of C .
payment
.total
matches the transaction amount that should have been displayed to the user. -
Verify that the value of C .
payment
.instrument
matches the payment instrument details that should have been displayed to the user.
-
-
9. Security Considerations
As this specification builds on top of WebAuthn, the WebAuthn Security Considerations are applicable. The below subsections comprise the current Secure Payment Confirmation-specific security considerations, where this specification diverges from WebAuthn.
9.1. Cross-origin authentication ceremony
A significant departure that Secure Payment Confirmation makes from WebAuthn is in allowing a third-party to initiate an authentication ceremony using credentials for a different Relying Party , and returning the assertion to the third party. This feature can expose Relying Parties to both login and payment attacks, which are discussed here.
9.1.1. Login Attack
As credentials created for Secure Payment Confirmation are valid WebAuthn credentials, it is possible that a Relying Party may wish to use the same credential for a given user for both login and payment. This allows a potential attack on the Relying Party’s login system, if they do not carefully verify the assertion they receive.
The attack is as follows:
-
The user visits
attacker.com
, which is or pretends to be a merchant site. -
attacker.com
obtains credentials for the user fromrelyingparty.com
, either legitimately or by stealing them fromrelyingparty.com
or another party with whomrelyingparty.com
had shared the credentials. -
attacker.com
initiates SPC authentication, and the user agrees to the transaction (which may or may not be legitimate). -
attacker.com
takes the payment assertion that they received from the API call, and sends it to the login endpoint forrelyingparty.com
, e.g. by sending a POST tohttps://relyingparty.com/login
. -
relyingparty.com
is employing faulty assertion validation code, which checks the signature but fails to validate the necessary fields (see below), and believes the login attempt to be legitimate. -
relyingparty.com
returns e.g. a login cookie toattacker.com
. The user’s account atrelyingparty.com
has now been compromised.
Relying Parties can guard against this attack in two ways.
Firstly, a Relying Party must always follow the correct assertion validation steps either for WebAuthn login or SPC payment as appropriate. In particular, the following fields can all be used to detect an inappropriate use of a credential:
-
CollectedClientData
.type
- "webauthn.get" for login, "payment.get" for SPC. -
CollectedClientData
.challenge
- this value should be provided by the Relying Party server to the site ahead of any call to either WebAuthn or SPC, and should be verified as matching an expected, appropriate, previously-provided value. -
CollectedClientData
.origin
- if SPC is being performed cross-origin, this value will contain the origin of the caller (e.g.attacker.com
in the above example).
Secondly,
a
Relying
Party
can
consider
keeping
their
payment
and
login
credentials
separate.
If
doing
this,
the
Relying
Party
should
only
register
credentials
for
Secure
Payment
Confirmation
on
a
subdomain
(e.g.
https//payment.relyingparty.com
),
and
should
keep
payment
credentials
and
login
credentials
separate
in
their
database.
payment
extension
specified
to
participate
in
SPC
authentication,
and
the
specification
may
be
updated
to
reflect
that
in
the
future.
In
both
implementation
and
specification
today,
a
credential
created
with
the
payment
can
be
used
for
login,
if
the
Relying
Party
wishes.
This
is
not
expected
to
change.
9.1.2. Payment Attack
A Secure Payment Confirmation assertion is essentially useless unless it is part of an ongoing online transaction.
A variety of mechanism protect against an attack where a malicious third-party, instead of attempting to hijack a user account, initiates an unauthorized payment using Secure Payment Confirmation credentials (obtained either legitimately or otherwise):
-
When the attacker initiates SPC, the user will be shown UI by the User Agent that clearly states the transaction details (including the payee and amount). The user is very likely to "cancel" in this scenario.
-
If the user does agree to the transaction, and completes the subsequent WebAuthn authentication ceremony, the attacker now has a signed SPC assertion for the Relying Party .
-
If the Relying Party is not expecting a transaction, it will reject the assertion.
-
If the Relying Party is expecting a transaction, it will detect an unfamiliar
challenge
and reject the assertion.
9.2. Merchant-supplied authentication data
A
The
bank
can
and
should
protect
against
spoofing
by
verifying
the
authentication
assertion
they
receive
to
ensure
it
aligns
with
the
transaction
details
provided
by
the
merchant.
That is because a consequence of this specification’s third-party authentication ceremony is that even in a valid transaction (i.e. one that the Relying Party is expecting), a third-party provides the transaction details that are shown to the user:
-
Transaction amount and currency
-
Payment instrument name and icon
-
Payee origin
This could lead to a spoofing attack, in which a merchant presents incorrect data to the user. For example, the merchant could tell the bank (in the backend) that it is initiating a purchase of $100, but then pass $1 to the SPC API (and thus show the user a $1 transaction to verify).
Secure Payment Confirmation actually makes defeating this kind of attack easier than it currently is on the web. In online payments today, the bank has to trust that the merchant showed the user the correct amount in their checkout flow (and any fraud discoveries are post-payment, when the user checks their account statement).
10. Privacy Considerations
As this specification builds on top of WebAuthn, the WebAuthn Privacy Considerations are applicable. The below subsections comprise the current Secure Payment Confirmation-specific privacy considerations, where this specification diverges from WebAuthn.
10.1. Registration in a Cross-Origin iframe
Unlike WebAuthn, this specification allows the creation of credentials in a cross-origin iframe (as long as the appropriate Permission Policy is set on the iframe). That is, if site A embeds an iframe from site B, with the " payment " policy set, then site B may initiate a credential creation for site B within that iframe.
NOTE: Allowing credential creation in cross-origin iframes is currently under discussion in the WebAuthn Working Group, and thus may move from this specification to WebAuthn in the future.
A
previously
described
attack
on
this
feature
exists.
In
it,
a
malicious
iframe
(
https://website.tracker
)
initiates
credential
creation,
attempting
to
trick
the
user
into
thinking
that
the
WebAuthn
credential
creation
is
for
logging
into
the
legitimate
parent
site
(
https://example.org
).
The
user
creates
the
credential.
The
malicious
actor
can
then
later
utilize
get()
in
a
cross-origin
iframe
(again,
timing
the
call
to
coincide
with
a
login
attempt
to
https://example.org
)
to
have
the
user
accidentally
identify
themselves
to
the
tracker
iframe.
This
attack,
however,
presumes
that
https://website.tracker
already
has
script
access
to
https://example.org
(in
order
to
create
the
attacker
iframe,
with
the
appropriate
permissions
set).
If
this
is
true,
then
https://website.tracker
can
already
directly
track
the
user,
for
example
by:
-
Identifying them from the username they provide when logging in to
https://example.org
, OR -
Creating a WebAuthn credential for
https://example.org
(in the main frame), saving that to ahttps://website.tracker
server, and later using that credential (again in the main frame) to identify and track the user.
https://website.tracker
to
track
the
user
across
multiple
parent
sites
that
it
is
directly
included
in,
using
the
credential
as
a
cross-site
identifier.
The
above
counter-claims
stand
up
less
well
there,
so
we
should
perhaps
remove
them.
In
the
absence
of
script
access
to
the
main
frame,
the
ability
for
a
malicious
iframe
to
perform
an
attack
like
this
seems
far
less
feasible.
Firstly,
the
main
frame
must
have
granted
the
malicious
iframe
permission
to
call
the
API.
Secondly,
the
iframe
has
no
way
to
know
when
the
user
is
logging
into
https://example.org
,
to
align
their
attack.
A consideration for a future version of this specification might be to additionally require consuming a transient activation for credential creation in a cross-origin iframe, to ensure that the user has at least interacted with an iframe attempting credential creation.
10.2. Probing for credential ids
As per WebAuthn’s section on Authentication Ceremony Privacy , implementors of Secure Payment Confirmation must make sure not to enable malicious callers (who now may not even be the Relying Party ) to distinguish between these cases:
-
A credential is not available.
-
A credential is available, but the user does not consent to use it.
For example, consider an implementation that does not download the payment instrument icon unless a credential matches. A caller could then provide an unique URL that they control for the payment instrument icon. If the URL is accessed then the caller can conclude that at least one of the passed credentials is available to the user.
10.3. Joining different payment instruments
If a Relying Party uses the same credentials for a given user across multiple payment instruments, this might allow a merchant to join information about payment instruments that might otherwise not be linked. That is, across two different transactions that a user U performs with payment instruments P1 and P2 (either on the same merchant M, or two colluding merchants M1 and M2), the merchant(s) may now be able to learn that P1 and P2 are for the same user.
For many current online payment flows this may not be a significant concern, as the user already provides sufficient information to do this joining anyway (e.g. their address), however it could become a privacy attack if, e.g., payment tokenization becomes commonplace.
One possible way to defeat this may be to hash the credential IDs with a random salt from the Account Provider ( Relying Party ):
-
Merchant requests the list of credential IDs from the Account Provider.
-
Account Provider generates a random salt.
-
Account Provider sends
[salt, hash(salt || credential ID)]
to the merchant. -
Merchant invokes SPC with the hashed credential ID and additionally passes the
salt
into the API. -
The browser generates
hash(salt || credential ID)
for each of the credential IDs that it has stored in the user profile. -
If any of the hashes match what the merchant provided, then a credential match has been found.
NOTE: If SPC relies on WebAuthn Conditional UI in the future, that API would have to support this salt-ing concept as the browser would not have a local list of credentials.
See this issue for more details.
10.4. Credential ID(s) as a tracking vector
Even for a single payment instrument, the credential ID(s) returned by the Relying Party could be used by a malicious entity as a tracking vector, as they are strong, cross-site identifiers. However in order to obtain them from the Relying Party , the merchant already needs an as-strong identifier to give to the Relying Party (e.g., the credit card number).
As above, a possible solution to this would be to hash the credential ID(s) with a random salt, making them non-consistent across calls.
11. Accessibility Considerations
User Agents implementing this specification should follow both WebAuthn’s Accessibility Considerations and PaymentRequest’s Accessibility Considerations .