1. 简介
本章节及其子章节为非规范性内容。
本规范定义了一个 API,使得在网页支付流程中能够使用强认证方法,并致力于提供与 [webauthn-3] 相同的认证优势和用户隐私保护,同时增强以满足支付处理的需求。
与 [webauthn-3] 类似,本规范定义了两个涉及用户的相关流程。第一个流程是 § 3 注册(原称“注册登记”),用于在用户与 依赖方之间建立关系。第二个流程是 § 4 认证 - 安全支付确认支付方式,当用户响应来自 依赖方(可能通过中介支付服务商)的挑战时,同意完成指定支付。
本规范的目标之一是在结账过程中减少认证阻力,其中一方面是为指定注册尽可能多地提升用户可认证次数。即获得 依赖方同意后,理想情况下用户可以“一次注册”,便可在任意商户来源(及支付服务商)完成认证,而不仅限于首次注册的商户来源。
因此,安全支付确认(SPC)的重要特性之一在于商户(或其他实体)可代表 依赖方发起认证流程。依赖方需在凭证创建期间主动选择允许此行为。
功能上,本规范为 PaymentRequest
API 定义了新的 支付方式,并新增 WebAuthn
扩展,以扩展 [webauthn-3],支持针对支付的数据结构、设备绑定,并放宽调用
API 的场景假设,便于在支付环境下使用。
1.1. 应用场景
虽然 [webauthn-3] 为 Web 提供了通用认证功能,但以下用例展示了本规范定义的针对支付扩展的作用。
我们假定利用密码学认证进行在线交易等一般性场景已广泛应用。
1.1.1. 交易确认的密码学证据
在许多线上支付系统,发行支付工具的主体(例如银行)会通过认证来降低欺诈。[webauthn-3] 及本规范使得使用认证器对重要的支付信息进行密码学签名变为可能,比如商户来源、交易金额和币种。作为 依赖方的银行可在授权时验证签名的支付信息。
如果银行仅使用 [webauthn-3],则需在
WebAuthn 的 challenge
字段中存储待验证的支付信息。这会带来以下问题:
-
这是对
challenge字段的误用(其原本用于防止重放攻击)。 -
没有相关的规范,每家银行都需自行设计支付信息在 challenge 中的格式及编码方式,增加部署难度并加剧割裂。
-
某些监管要求必须证明用户确实已看见并同意该支付信息。单用 [webauthn-3] 不提供此类展示:challenge 字段内信息无任何规范的用户体验指引。
上述局限促成了以下安全支付确认(SPC)行为:
-
challenge 字段仅用于防止重放攻击,与普通 [webauthn-3] 相同。
-
SPC 对支付信息指定了统一格式,有助于通用验证代码和测试套件开发。
-
SPC 保证用户代理以网站(或恶意注入 JS 代码)无法绕过的方式向用户展示支付信息。
-
支付信息会包含在
CollectedClientData字典中,无法被 JavaScript 篡改。
注意:当下支付生态中的银行等主体通过 TLS、iframe 等 Web 功能足以信任浏览器环境下的支付。目前规范旨在进一步提升 Web 支付的安全性与易用性。
-
1.1.2. 商户对认证的控制
商户希望减少结账过程中的用户流失,尤其是降低认证阻力。依赖方(如银行)一般使用 [webauthn-3] 进行用户认证时,通常是在 iframe 内完成。但商户更希望主导用户认证过程体验,同时也能让 依赖方验证认证结果。
此类局限推动了安全支付确认(SPC)下的新行为:
-
通过 SPC,除 依赖方 外的其他方也可以代表依赖方使用认证凭证进行认证,依赖方随后可验证认证结果。
上述特性带来的额外好处是依赖方自身不必再开发认证前端体验,支付服务商可能会为商户开发此类体验。
注意:希望自定义认证体验的依赖方仍可在 iframe 中用 SPC 完成。
1.1.3. 设备绑定的密码学证据
在支付行业,设备持有信号是重要的二要素。WebAuthn 支持同步密钥,单一凭证可跨多设备使用(参见 Web Authentication § 1.2.1 消费者多设备凭证)。虽然同步提升了登录体验,有声音担忧仅靠同步密钥不能满足某些监管环境下“设备持有”要求。
上述担忧推动本规范引入用户代理生成的辅助 公私钥对,私钥仅保存在一个设备内且仅由该设备使用。此类密钥及其在 SPC 中的应用称为 浏览器绑定密钥。
1.2. API 示例使用场景
本节举例介绍安全支付确认常见场景及 API 使用代码,实际应用不限于以下流程。
1.2.1. 结账过程中的注册
这是首次流程,用户在某商户结账时,发卡银行会新建并存储一个凭证。
-
用户访问
merchant.example,选购商品后进入结账流程,录入支付工具信息,并确认付款(例如点击“支付”按钮)。 -
商户与发卡银行进行带外通信(例如使用其他协议)。发卡银行请求用户验证,并提供银行控制的 URL 供商户在 iframe 内打开。
-
商户在
bank.example打开一个带allow属性值为 "publickey-credentials-create" 的 iframe。 -
iframe 内,发卡银行通过传统方式(如短信验证码)确认用户身份,随后邀请用户注册 SPC 认证以便未来支付。
-
用户同意(例如点击银行界面的“注册”按钮),银行在 iframe 内运行如下代码。
-
用户进行 WebAuthn 注册流程,新凭证创建后返回给银行,银行服务端与用户和支付工具关联存储。
-
验证流程完成后银行 iframe 关闭,商户继续完成用户结账流程。
如下为用户注册代码样例:
if ( ! window. PublicKeyCredential) { /* 客户端不支持。请处理错误。 */ } const publicKey= { // challenge 由银行服务端创建并发送到 iframe。 challenge: new Uint8Array([ 21 , 31 , 105 /* 服务器生成的另外 29 个随机字节 */ ]), // 依赖方: rp: { name: "Fancy Bank" , }, // 用户: user: { // WebAuthn要求。本信息非SPC必须,但银行服务端可用于识别用户。 // 同一用户如信息不一致则可能创建多个凭证,影响凭证选择体验。 id: Uint8Array. from ( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "jane.doe@email.example" , displayName: "Jane Doe" , }, // 本例依赖方接受 ES256 或 RS256 凭证,但更偏好 ES256。 pubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" }, { type: "public-key" , alg: - 257 // "RS256" } ], authenticatorSelection: { userVerification: "required" , residentKey: "required" , authenticatorAttachment: "platform" , }, timeout: 360000 , // 6分钟 // 表明这是SPC凭证。当前必须,浏览器据此关联SPC,也支持跨源iframe创建。 // // 后续规范可能取消该扩展的必需性。 extensions: { "payment" : { isPayment: true , // 可选的算法允许列表。未指定时使用 pubKeyCredparams,默认 ES256与RS256。 // 本例允许ES256和RS256,偏好RS256。 browserBoundPubKeyCredParams: [ { type: "public-key" , alg: - 257 // "RS256" }, { type: "public-key" , alg: - 7 // "ES256" } ] } } }; // 注意:以下调用会促使认证器显示界面。 navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // 将新凭证信息发送到服务器进行校验和注册。 }). catch ( function ( err) { // 未找到可用认证器或用户拒绝授权,需妥善处理。 });
1.2.2. 商户网站认证
当用户已注册凭证,在进行交易且发卡银行和商户希望使用安全支付确认时,流程如下。
-
用户访问
merchant.example,选购商品后进入结账流程,输入支付工具信息,确认付款(如点击“支付”按钮)。 -
商户与支付工具发卡银行进行带外通信(如使用其他协议)。发卡银行请求用户验证,同时告知商户已支持 SPC,并提供调用 API 所需信息。包括挑战值和与该用户及支付工具绑定的所有凭证ID。
-
商户运行下方示例代码。
-
用户在 SPC 界面同意支付信息,并完成后续 WebAuthn 认证流程。签名密文返回给商户(包含
AuthenticationExtensionsPaymentOutputs的浏览器绑定密钥输出)。 -
商户将签名密文带外发送给发卡银行。银行验证密文,并确认用户有效、所显示的支付信息,以及用户已经同意本次交易。银行授权交易,商户完成结账流程。银行保存 浏览器绑定密钥的公钥,
browserBoundPublicKey。
如下为用户身份认证代码示例。示例代码假定支持 await/async,以便简化 promise 处理流程。
/* securePaymentConfirmationAvailability 表示浏览器是否支持SPC */ /* 不表示用户当前设备上是否有可用凭证。 */ const spcAvailable= PaymentRequest&& PaymentRequest. securePaymentConfirmationAvailability&& ( await PaymentRequest. securePaymentConfirmationAvailability()) === 'available' ; if ( ! spcAvailable) { /* 浏览器不支持SPC,商户应回退到传统流程。 */ } const request= new PaymentRequest([{ supportedMethods: "secure-payment-confirmation" , data: { // 从银行获取的凭证ID列表 credentialIds, rpId: "fancybank.example" , // 挑战值也是由银行获取 challenge: new Uint8Array([ 21 , 31 , 105 /* 银行生成的其他29个随机字节 */ ]), instrument: { displayName: "FancyBank Platinum Card" , details: "****1234 | 01/29" , icon: "https://fancybank.example/card-art.png" , }, payeeName: "Merchant Shop" , payeeOrigin: "https://merchant.example" , paymentEntitiesLogos: [ { url: "https://fancybank.example/logo.png" , label: "Fancy Bank" , }, { url: "https://securenetwork.example/logo.png" , label: "Secure Network" , }, ], // 调用方请求本地化体验 locale: [ "en" ], timeout: 360000 , // 6分钟 // 可选的算法列表,默认ES256和RS256,本例允许ES256和RS256,偏好ES256。 // 浏览器绑定密钥已存在时不会创建,仅当需要新建时使用此列表。 browserBoundPubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" }, { type: "public-key" , alg: - 257 // "RS256" } ] }], { total: { label: "Total" , amount: { currency: "USD" , value: "5.00" , }, }, }); try { const response= await request. show(); await response. complete( 'success' ); // response.data 为 PublicKeyCredential,clientDataJSON 包含由发卡银行验证的交易数据。 /* 将 response.data 发送给发卡银行进行验证 */ } catch ( err) { /* SPC无法使用,商户应回退到传统流程 */ }
2. 术语
- SPC 凭证
-
一种可用于本规范行为的 WebAuthn 凭证。
本规范不限制依赖方(Relying Party)将 SPC 凭证用于其它认证流程(如登录)。
注意: 当前版本规范要求 依赖方主动选择凭证是否可用于第一方或第三方场景。后续长远目标是所有 WebAuthn 凭证 在第一方场景(即在 依赖方域名下)均可支持SPC,仅需对第三方场景时才需选择允许。
- 第三方启用SPC凭证
-
一种 SPC 凭证,依赖方(Relying Party) 在凭证创建时主动选择允许其被除依赖方外的其他方用于安全支付确认认证场景。
- 静默判断SPC凭证是否已启用第三方使用步骤
-
一种尚未定义的流程,用户代理可据 依赖方标识符 和 凭证ID,静默(无用户交互)判断凭证ID对应的凭证是否为 第三方启用SPC凭证。
注意: 参见 WebAuthn issue 1667。
- 静默判断凭证是否可用于当前设备的步骤
-
一种尚未定义的流程,用户代理可据 依赖方标识符 和 凭证ID,静默(无用户交互)判断该凭证ID对应的凭证是否可在当前设备被使用(即能被 WebAuthn Get 调用成功)。
用户代理可据此只在有可能成功完成交易时条件性展示交易确认界面。
注意: 此属性通常要求 SPC 凭证为 可发现凭证,因此规范中当前要求此特性。
注意: 此属性与WebAuthn 条件UI提案非常相似,SPC与之可共享底层API实现。
- 浏览器绑定密钥
-
一个由用户代理绑定到单一设备的公私密钥对,除 WebAuthn 凭证外还能对交易详情进行签名。
- 密钥对
-
注意: 公钥和私钥为 IANA COSE 算法注册表 [IANA-COSE-ALGS-REG]引用的密码算法相关参数。
注意: 注册时公钥部分会返回:
CollectedClientAdditionalPaymentRegistrationData.browserBoundPublicKey支付断言时会返回CollectedClientAdditionalPaymentData.browserBoundPublicKey。注意: 私钥用于生成密码签名(包含于
BrowserBoundSignature.signature),用户代理不导出私钥,并可将其存储于设备安全元件。
3. 注册
为用户注册安全支付确认时,依赖方应调用
navigator.credentials.create(),
并指定
payment
WebAuthn 扩展参数。
注意: 本规范定义扩展,以支持浏览器在缺乏 条件UI时缓存SPC凭证ID。后续WebAuthn版本如具备相关能力,SPC可取消此扩展要求。注意扩展下的SPC凭证本质仍为完整WebAuthn凭证。
注意: 注册时 Web Authentication 需提供
name
和
displayName,
但根据user成员定义,实现不要求后续认证流程展示。截止2023年10月,name展示更一致。开发者需关注实现动态。
4. 认证 - 安全支付确认支付方式
要通过安全支付确认进行付款认证,本规范定义了:
-
一个 支付处理器,即 安全支付确认支付处理器,用来处理认证指定支付的请求。
-
该支付处理器的标准化支付方式标识符为 "secure-payment-confirmation"。
安全支付确认支付处理器确认用户交易后, 会执行认证流程,验证用户并创建代表本认证流程的签名数据片段。
总的来说,安全支付确认的认证同 [webauthn-3] 类似,唯一重要概念变化是安全支付确认允许第三方(如商户)代表依赖方发起认证流程,传入从依赖方其他渠道获得的凭证。详见 § 1.1.2 商户对认证的控制。
注意: 为快速支持初期SPC实验,该API设计基于 Payment Request 和 Payment Handler APIs 的现有实现。现已普遍认为应探索独立于 Payment Request 的 SPC 设计。因此预计(暂无具体时间表)SPC将脱离原有 Payment Request 实现。对于开发者,这将提升特性检测、调用及API其他使用体验。
4.1. 在 [payment-method-id] 注册
向 标准支付方式注册表 及 [payment-method-id] 增加如下内容:
- "secure-payment-confirmation"
-
安全支付确认规范。
4.2. 修改 Payment Request 构造函数
在 PaymentRequest 对象构造函数
的步骤中,步骤4.3后新增:
-
处理支付方式:[子步骤1-3 遗略]
-
若seenPMIs包含 "secure-payment-confirmation" 且 seenPMIs 长度大于1,则抛出
RangeError异常。
-
4.3. 修改用户激活要求
在 PaymentRequest.show()
方法步骤中,修改步骤2和3:
-
否则,消耗用户激活(即消费关联全局对象的激活状态)。
注意: 允许用户代理无需用户激活,可支持重定向认证流程(如重定向后无用户激活)。安全相关见 § 11.4 用户激活要求的缺失。
4.4. SecurePaymentConfirmationRequest
字典
dictionary SecurePaymentConfirmationRequest {required BufferSource ;challenge required USVString ;rpId required sequence <BufferSource >;credentialIds required PaymentCredentialInstrument ;instrument unsigned long ;timeout USVString ;payeeName USVString ;payeeOrigin sequence <PaymentEntityLogo >;paymentEntitiesLogos AuthenticationExtensionsClientInputs ;extensions sequence <PublicKeyCredentialParameters >;browserBoundPubKeyCredParams sequence <USVString >;locale boolean ; };showOptOut
SecurePaymentConfirmationRequest
字典包含如下成员:
challenge-
由依赖方服务端生成的随机 challenge,用于防止重放攻击。
rpId-
凭证的依赖方标识符。
credentialIds-
指定支付工具相关凭证ID列表。
instrument-
注册和签名时用于展示的支付工具名称及图标描述。
timeout-
签名支付详情请求最大等待毫秒数,不超过1小时。默认值和范围由用户代理定义。Web Authentication 可参见超时相关指导。
payeeName-
本次SPC调用收款人显示名(如商户名)。可选,或与
payeeOrigin一同或单独提供。 payeeOriginpaymentEntitiesLogos-
代表本次SPC调用所涉及支付实体的可选logo列表,按展示优先级递减排序。用户代理不要求全部都展示,详见 § 4.8 检查可否支付步骤。
注意:本规范未规定logo呈现方式,旨在保留用户代理渲染控制权,并允许最佳展示信息。logo顺序很重要,开发者可通过调整顺序获得期望结果。
extensions-
用于传递凭证的任何WebAuthn扩展。调用者无需指定支付扩展,会自动添加。
browserBoundPubKeyCredParams-
浏览器绑定密钥使用的加密算法类型限制列表。
注意: 仅当需创建浏览器绑定密钥时此成员才生效。
locale-
可选语言标签列表(见 [BCP47]),按优先级排序,标识网站区域偏好, 即语言优先列表 [RFC4647]。用户代理可据此与调用方进行语言协商和区域相关格式化。
showOptOut-
是否在交易确认界面给用户提供选择退出机会。可选,默认false。
4.5. 支付方式附加数据类型
本支付方式的附加数据类型为
SecurePaymentConfirmationRequest。
4.6. 检查安全支付确认是否可用
在PaymentRequest
上添加了静态API,让开发者能简便地检查安全支付确认是否可用。该方法securePaymentConfirmationAvailability()
返回枚举类型成员,指明安全支付确认是否可用或不可用,并说明底层原因。枚举输出旨在帮助开发者为用户提供身份认证选项指引和提示。
enum {SecurePaymentConfirmationAvailability "available" ,"unavailable-unknown-reason" ,"unavailable-feature-not-enabled" ,"unavailable-no-permission-policy" ,"unavailable-no-user-verifying-platform-authenticator" , };partial interface PaymentRequest {static Promise <SecurePaymentConfirmationAvailability >(); };securePaymentConfirmationAvailability
SecurePaymentConfirmationAvailability
枚举包含如下成员:
available-
指示用户代理认为安全支付确认API在当前帧可用。
注意: 此结果不代表某个具体SPC凭证是否可用。
unavailable-unknown-reason-
指示安全支付确认API在当前帧不可用,原因未知。用户代理可随时选择返回此结果而非更具体原因,以保护用户隐私。
unavailable-feature-not-enabled-
指示安全支付确认API在当前帧不可用,因为未启用相关功能。
unavailable-no-permission-policy-
指示安全支付确认API在当前帧不可用,因为缺少 "payment" 权限策略。
unavailable-no-user-verifying-platform-authenticator-
指示安全支付确认API在当前帧不可用,因为没有可用的用户验证平台认证器。
注意: 此信息可通过调用
isUserVerifyingPlatformAuthenticatorAvailable获取,这一API中为开发便利性而包含。
在特定securePaymentConfirmationAvailability()
调用时,用户代理须执行如下步骤。用户代理可随时选择返回
"unavailable-unknown-reason",
以保护用户隐私或无法完成某步骤时。
-
如用户代理不支持安全支付确认,或支持但通过某种机制被禁用,则返回 "
unavailable-feature-not-enabled"。 -
如 document 未启用 "payment" 权限策略,则返回 "
unavailable-no-permission-policy"。 -
如无用户验证平台认证器 可用,则返回 "
unavailable-no-user-verifying-platform-authenticator"。 -
如有任何其他原因致使安全支付确认在 document 下无法工作,则返回 "
unavailable-unknown-reason"。 -
返回 "
available"。
此 API 允许开发者如下检查是否需要发起SPC流程:
const spcAvailable= PaymentRequest&& PaymentRequest. securePaymentConfirmationAvailability&& await PaymentRequest. securePaymentConfirmationAvailability() === 'available' ;
注意: 建议使用静态securePaymentConfirmationAvailability
方法做SPC特性检测,而不是在已构建的 PaymentRequest 实例上调用canMakePayment。
注意: 本API涉及隐私问题,详见 § 12.5 通过securePaymentConfirmationAvailability指纹识别。
4.7. 验证支付方式数据的步骤
对于本支付方式,输入 PaymentRequest
request 和 SecurePaymentConfirmationRequest
data 所需的 验证支付方式数据的步骤如下:
测试
-
如果 data["
credentialIds"] 为空, 抛出RangeError。 -
针对 data["
credentialIds"] 中每个 id:-
如果 id 为空,则抛出
RangeError。
-
-
若 data["
instrument"]["displayName"] 为空,则抛出TypeError。 -
若 data["
instrument"]["icon"] 为空,则抛出TypeError。 -
对 data["
instrument"] ["icon"] 运行网址解析器。 若解析失败,抛出TypeError。 -
若 data["
instrument"]["details"] 有值但为空,则抛出TypeError。 -
若 data["
payeeName"] 和 data["payeeOrigin"] 均未提供, 则抛出TypeError。 -
如果 data["
payeeName"] 和 data["payeeOrigin"] 有值但为空,则抛出TypeError。 -
如 data["
payeeOrigin"] 有值:-
让 parsedURL 为对 data["
payeeOrigin"] 运行网址解析器的结果。 -
如 parsedURL 解析失败,则抛出
TypeError。
-
-
如 data["
paymentEntitiesLogos"] 有值且非空: -
注意:
locale与特定输入项绑定的语言或方向元数据不同,代表调用方请求的本地化体验而非对某个字符串值的断言。更多讨论见 § 14 国际化考虑。
4.8. 检查能否进行支付的步骤
对于本支付方式,输入 SecurePaymentConfirmationRequest
data 所需的 检查能否进行支付的步骤如下:
测试
-
如 data["
payeeOrigin"] 有值:-
让 parsedURL 为对 data["
payeeOrigin"] 运行网址解析器的结果。 -
断言 parsedURL 不是失败。
-
断言 parsedURL 的 scheme 为 "
https"。
注意:这些前置条件已在 验证支付方式数据的步骤进行过检查。
-
将 data["
payeeOrigin"] 设置为 parsedURL 的 origin序列化值。
-
-
拉取icon对应的图片资源,传递 «["
src" → data["instrument"]["icon"]]» 作为 image;若拉取失败:-
如 data["
instrument"]["iconMustBeShown"] 为true,则返回false。 -
否则,将 data["
instrument"]["icon"] 设为空字符串。注意:这样可让RP知晓指定icon未能展示,因输出
instrument的 icon 字段为空。
注意:图片资源必须无论凭证是否匹配均要拉取,以防推测凭证是否存在。
-
-
用户代理可选地从 data["
paymentEntitiesLogos"] 从后往前移除条目。注意:这样允许用户代理控制展示logo数量,并保持logo优先级排序的语义。
-
对 data["
paymentEntitiesLogos"] 中每个 logo:-
拉取logo的图片资源,传递 «["
src" → logo["url"]]» 作为 image,并解码结果。 -
如拉取或解码失败,将 logo["
url"] 设为空字符串。注意:这样让RP知晓指定logo未能展示,因输出
paymentEntitiesLogos的对应logo条目的 url 字段为空。
注意:Logo图片必须无论凭证是否匹配均要拉取,以防推测凭证是否存在。
-
-
对 data["
credentialIds"] 中每个 id:-
运行静默判断凭证是否可用于当前设备的步骤,传递 data["
rpId"] 和 id。 如结果为false,则从 data["credentialIds"] 移除 id。 -
如 data["
rpId"] 不等于 request 的origin, 则运行静默判断SPC凭证是否已启用第三方使用步骤,传递 data["rpId"] 和 id。如结果为false,则从 data["credentialIds"] 移除 id。
-
-
返回
true。
4.9. 显示交易确认界面
当调用 PaymentRequest.show()
并选中 安全支付确认支付处理器(该算法第19-24步),用户代理必须向用户展示界面,允许用户选择是否及如何继续。
4.9.1. 向用户展示的信息
为避免限制用户代理实现选择,本规范不强制要求特定界面。但为使 依赖方能信任 CollectedClientPaymentData
所含信息,
用户代理必须确保下列信息被传递给用户,并收集到用户对认证的同意:
-
若有,则展示
payeeName。 -
若有,则展示
payeeOrigin。 -
展示支付工具
instrument详情,包括 displayName、details 及 icon。 如资源无法获取或解码,则用户代理可以不显示icon或显示通用支付工具图标。注意:如指定icon无法获取或解码,则此处
iconMustBeShown必须为false, 否则 检查能否进行支付的步骤此前就会失败。 -
若非空,展示
url对应的 logo, 来自paymentEntitiesLogos。-
用户代理不必显示每个
label,但应在无障碍功能用到。所有label仍会被包括且加入签名用于CollectedClientAdditionalPaymentData。
-
用户代理可利用 locale
信息(如有)来展示与网站一致的本地化语言和格式界面。
如 showOptOut
为 true,用户代理必须让用户能选择对该 依赖方
退出流程。
4.9.2. 交易确认界面结果
用户代理必须允许用户指明是否及如何继续的选项:
- 用户希望继续付款,并用 SPC凭证 认证
-
对交互中的
PaymentRequest执行 用户接受支付请求算法。 - 用户希望继续付款,但因 data["
credentialIds"] 为空无法使用 SPC凭证,或者主动选择不用 SPC凭证 -
运行下列步骤:
-
设 data["
credentialIds"] 为空列表。注意:此举将使
PaymentRequest.show()被拒绝(NotAllowedError DOMException),参考 响应支付请求的步骤。 -
对交互中的
PaymentRequest执行 用户接受支付请求算法。
-
- 用户不希望继续付款
-
对交互中的
PaymentRequest执行 用户终止支付请求算法。注意:此举会使
PaymentRequest.show()被拒绝(AbortError DOMException)。 - 用户希望对该
依赖方选择退出 -
用 "
OptOutError" DOMException 拒绝PaymentRequest.show(),参见 § 12.6 用户选择退出。注意:只有当
showOptOut设为true时用户才能看到该选项。
4.9.3. 测试自动化支持
如 当前交易自动化模式不是
"none",用户代理应首先验证自身处于自动化上下文(见 WebDriver安全注意事项)。随后,用户代理应跳过上述信息传递及用户同意收集,根据 当前交易自动化模式值执行如下:
- "
autoAccept" -
视为用户已看见交易详情并接受。
- "
autoChooseToAuthAnotherWay" -
视为用户已看见交易详情并接受,但明确表示不希望用 SPC凭证认证。如 data["
credentialIds"] 为空,则等同于 "autoAccept"。 - "
autoReject" -
视为用户已看见交易详情并拒绝(即不继续交易)。
- "
autoOptOut" -
视为用户已看见交易详情并选择退出。
4.10. 响应支付请求的步骤
对于本支付方式,给定 PaymentRequest
request 和 SecurePaymentConfirmationRequest
data,其 响应支付请求的步骤为:
注意:仅当用户接受交易确认界面时才会执行本步骤,由 用户接受支付请求算法调用。
-
如 data["
credentialIds"] 为空, 抛出 "NotAllowedError" DOMException。 这在用户无法或不愿用SPC认证时保护认证流程隐私。注意:此处抛出异常,会导致
PaymentRequest.show()被拒绝(NotAllowedError DOMException)。 -
令 topOrigin 为 request 的顶级origin。
-
令 payment 为新
AuthenticationExtensionsPaymentInputs字典,字段为:isPayment-
值为
true。 rpId-
data["
rpId"] topOrigin-
topOrigin
payeeName-
data["
payeeName"] 如有则用,否则省略。 payeeOrigin-
data["
payeeOrigin"] 如有则用,否则省略。 paymentEntitiesLogos-
data["
paymentEntitiesLogos"] 如非空则用,否则省略。当前规范仅支持每个 PaymentEntityLogo 一个URL,直接复制并签名数据结构足以显示所展示内容。未来规范或对每个 PaymentEntityLogo 支持多个URL(例如暗黑模式)。如有,将需指明实际向用户展示的URL。
total-
request.[[details]]["
total"] instrument-
data["
instrument"] browserBoundPubKeyCredParams-
data["
browserBoundPubKeyCredParams"]
-
令 extensions 为新
AuthenticationExtensionsClientInputs字典,payment成员为 payment,其它成员从 data["extensions"] 设置。 -
令 publicKeyOpts 为新
PublicKeyCredentialRequestOptions字典,其字段为:challenge-
data["
challenge"] timeout-
data["
timeout"] rpId-
data["
rpId"] userVerificationextensions-
extensions
注意:本算法将"userVerification"设为"required",是因Chrome初始实现仅支持该值。后续限制可能变化。工作组欢迎提出支持其它值(如"preferred"或"discouraged")的使用场景。
-
对 data["
credentialIds"] 中每个 id:-
令 descriptor 为新
PublicKeyCredentialDescriptor字典,其字段为:typeid-
id
transports-
长度为1的序列,唯一成员为
internal。
-
将 descriptor 添加到 publicKeyOpts["
allowCredentials"]。
-
-
令 outputCredential 为执行 请求凭证算法(传递«["
publicKey" → publicKeyOpts]»)的结果。注意:Chrome最初实现不会将 data.credentialIds 全部传入请求凭证算法,仅传入已匹配当前设备的一个。
注意:此操作会触发 [webauthn-3] 的 Get 行为。
-
返回 outputCredential。
5.
WebAuthn 扩展 - "payment"
此客户端 注册扩展 与 认证扩展分别表示凭证是用于创建或用于安全支付确认。
对于注册,此扩展允许浏览器识别和缓存安全支付确认凭证ID。对于认证,此扩展允许第三方代表 依赖方执行认证流程,并将交易信息加入签名密文中。
注意,网站不应直接用此扩展调用
navigator.credentials.get();
认证时扩展仅能通过
PaymentRequest
并指定 "secure-payment-confirmation" 支付方式访问。
注意: 过去,payment 扩展允许跨域iframe创建凭证。而现在从 WebAuthn PR
#1801 开始,WebAuthn 默认允许该行为。
测试
此测试并不直接对应规范某一行,而是检验是否可以在跨域 iframe 内触发认证。规范未明确禁止即可实现此行为。
- 扩展标识符
-
payment - 操作适用范围
- 客户端扩展输入
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsPaymentInputs ; };payment dictionary {AuthenticationExtensionsPaymentInputs boolean ;isPayment sequence <PublicKeyCredentialParameters >; // 仅用于认证。browserBoundPubKeyCredParams USVString ;rpId USVString ;topOrigin USVString ;payeeName USVString ;payeeOrigin sequence <PaymentEntityLogo >;paymentEntitiesLogos PaymentCurrencyAmount ;total PaymentCredentialInstrument ; };instrument isPayment-
表示扩展已激活。
rpId-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
topOrigin-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
payeeName-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
payeeOrigin-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
paymentEntitiesLogos-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
total-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
instrument-
仅在认证时使用,注册时不使用,且不应由网页开发者直接设置。
browserBoundPubKeyCredParams-
用于限制浏览器绑定密钥加密算法类型的允许列表。认证时网页开发者应设置
SecurePaymentConfirmationRequest.browserBoundPubKeyCredParams。注意: 当本成员未设置时,默认值为
PublicKeyCredentialCreationOptions.pubKeyCredParams。
- 客户端扩展处理(注册)
-
创建新凭证时(createCredential):
-
第3步后插入以下步骤:
-
如果下列任一条件成立:
-
pkOptions["
authenticatorSelection"]["authenticatorAttachment"] 不为 "platform"。 -
pkOptions["
authenticatorSelection"]["residentKey"] 不为 "required" 或 "preferred"。 -
pkOptions["
authenticatorSelection"]["userVerification"] 不为 "required"。
则抛出
TypeError。注意:这些值目前为硬编码,源自Chrome初始实现。当前限制可能变化,欢迎提出支持其他值的场景。
-
-
-
第13步前(创建
CollectedClientData前)。测试
-
令 bbk_allowed_algorithms 为
browserBoundPubKeyCredParams。 -
如
browserBoundPubKeyCredParams为空,令 bbk_allowed_algorithms 为PublicKeyCredentialCreationOptions.pubKeyCredParams。 -
令 (bbk_and_algorithm, bbk_id) 为用 bbk_allowed_algorithms 创建密钥对的结果。
-
如 (bbk_and_algorithm, bbk_id) 为 null,跳过与 bbk_and_algorithm 和 bbk_public_key 有关的步骤。
-
令 bbk_public_key 为用 bbk_and_algorithm 获取浏览器绑定公钥的结果。
-
-
第13步,将创建
CollectedClientData换成CollectedClientPaymentData,包含以下字段:payment-
初始化为
CollectedClientAdditionalPaymentRegistrationData,字段有:browserBoundPublicKey-
bbk_public_key,COSE_Key 编码的 公钥。
- 其它字段
-
其余字段按原13步操作。
-
在 第22步,判断“有认证器指示成功”时返回 pubKeyCred 前:
-
用 bbk_id 与 pubKeyCred.
[[identifier]]绑定密钥对。如失败,返回UnknownError。 -
令 payment_outputs 为
AuthenticationExtensionsPaymentOutputs,包含:browserBoundSignature-
初始化为
BrowserBoundSignature,字段有:
-
[[clientExtensionsResults]]["payment"] 设为 payment_outputs。
-
-
- 客户端扩展处理(认证)
-
当用
AuthenticationExtensionsPaymentInputsextension_inputs 断言时:-
如不在 "secure-payment-confirmation" 支付处理器内,返回 "
NotAllowedError" DOMException。注意:防止网站不通过交易界面绕过SPC能力。
-
在
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)期间:-
跳过6.1步(比较 options.rpId 与 effectiveDomain)。
注意:由此可支持跨域认证流程,详见 § 1.1.2 商户对认证的控制。
-
第10步前(创建
CollectedClientData前)。-
令 allowed_algorithms 为
SecurePaymentConfirmationRequest.browserBoundPubKeyCredParams。 -
令 bbk_and_algorithm 为用 credential_id 与 allowed_algorithms 获取或创建浏览器绑定密钥的结果。
-
-
第10步,将创建
CollectedClientData换成CollectedClientPaymentData,包含:-
type设为 "payment.get" -
payment设为新CollectedClientAdditionalPaymentData,字段有:rpId-
extension_inputs["
rpId"] topOrigin-
extension_inputs["
topOrigin"] payeeName-
extension_inputs["
payeeName"],有则用,否则省略。 payeeOrigin-
extension_inputs["
payeeOrigin"],有则用,否则省略。 paymentEntitiesLogos-
extension_inputs["
paymentEntitiesLogos"],有则用,否则省略。 total-
extension_inputs["
total"] instrument-
extension_inputs["
instrument"] browserBoundPublicKey-
如 bbk_and_algorithm 非 null,则用 bbk_and_algorithm 获取浏览器绑定公钥结果。否则不设置。
-
其余字段按原10步设置。
-
-
“有认证器指示成功”时,在第2步设置
[[clientExtensionsResults]]:-
令 payment_outputs 为
AuthenticationExtensionsPaymentOutputs,字段有:browserBoundSignature-
如 bbk_and_algorithm 非 null,则初始化
BrowserBoundSignature,字段有:
-
设置
[[clientExtensionsResults]]["payment"] 为 payment_outputs。
-
-
-
- 客户端扩展输出
-
partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsPaymentOutputs ; };payment dictionary {AuthenticationExtensionsPaymentOutputs BrowserBoundSignature ; };browserBoundSignature dictionary {BrowserBoundSignature required ArrayBuffer ; };signature browserBoundSignature-
浏览器绑定签名过程的输出。
signature-
浏览器绑定签名流程输出。
- 认证器扩展处理
-
无
5.1. CollectedClientPaymentData
字典
dictionary CollectedClientPaymentData :CollectedClientData {required (CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData ); };payment
CollectedClientPaymentData
字典继承自
CollectedClientData。
包含如下额外字段:
payment-
待签名的附加支付信息。
5.2. CollectedClientAdditionalPaymentData
字典
dictionary CollectedClientAdditionalPaymentData {required USVString ;rpId required USVString ;topOrigin USVString ;payeeName USVString ;payeeOrigin sequence <PaymentEntityLogo >;paymentEntitiesLogos required PaymentCurrencyAmount ;total required PaymentCredentialInstrument ;instrument USVString ; };browserBoundPublicKey
CollectedClientAdditionalPaymentData
字典包含如下字段:
rpId-
创建凭证的 依赖方标识。
注意:由于历史原因,有的实现还会包含
rp。如同时存在,rp和rpId必须相同。 topOrigin-
请求签名交易详情的顶层上下文来源。
payeeName-
展示给用户的收款方名称(如有)。
payeeOrigin-
展示给用户的收款方来源(如有)。
paymentEntitiesLogos-
交易对话框中展示给用户的logo(如有)。代表促成本次交易的实体。
total-
PaymentCurrencyAmount,对应 [payment-request] 中
total字段。 instrument-
展示给用户的支付工具信息。
browserBoundPublicKey-
浏览器绑定密钥公钥的 base64url 编码。详见 WebAuthn 的 Base64url 编码。
注意 paymentRequestOrigin 字段未出现在
CollectedClientAdditionalPaymentData
内,因为调用帧的origin已包含在 CollectedClientData
里(参见 [webauthn-3])。
5.3. CollectedClientAdditionalPaymentRegistrationData
字典
dictionary CollectedClientAdditionalPaymentRegistrationData {USVString ; };browserBoundPublicKey
CollectedClientAdditionalPaymentRegistrationData
字典包含如下字段:
browserBoundPublicKey-
浏览器绑定密钥公钥的 base64url 编码。详见 WebAuthn 的 Base64url 编码。
6. 浏览器绑定密钥存储
这是由 用户代理持有的内部组件,管理依赖平台的加密密钥对,包括它们与 SPC凭证(即passkey)的关联。 本节说明 浏览器绑定密钥存储及其密钥对创建、绑定、检索和签名过程。
注意: 浏览器绑定密钥存储需要生成密钥对、检索密钥对、导出公钥、生成签名。许多操作系统都提供相关API,并将私钥存储于设备安全元件(如有)。如 Android KeyStore、 Apple CryptoKit 或 Windows Cryptography API: Next Generation。
浏览器绑定密钥存储包含如下内容:
- browser_bound_map
-
从 Credential ID 到密钥对标识符的映射。
- keypair_map
-
从字节数组(密钥对标识符)到由公私密钥对和算法标识符
COSEAlgorithmIdentifier组成的二元组映射。注意: 用户代理可调用加密API以实现类似 keypair_map 功能,则该部分工作可委托给加密API。
6.1. 创建密钥对
要在给定 PublicKeyCredentialParameters,
allowed_algorithms 时 创建密钥对,返回包含密钥对和其 COSEAlgorithmIdentifier
及密钥对标识字节数组的二元组,请按如下步骤执行:
注意:根据允许算法或默认列表生成密钥对。
-
如果 allowed_algorithms 为空, 则使用如下默认列表:
-
type=PublicKeyCredentialType且alg= -7 ("ES256") -
type=PublicKeyCredentialType且alg= -257 ("RS256")
-
-
移除 allowed_algorithms 中类型不是
PublicKeyCredential的条目。 -
移除用户代理不支持的 allowed_algorithms 条目。
注意: 不同平台用户代理支持的加密算法不同。
-
如 allowed_algorithms的长度为零则返回null。
注意:此时用户代理不会输出任何浏览器绑定内容。
-
如 allowed_algorithms的长度大于零:
-
令 chosen_algorithm 为 allowed_algorithms[0]。
-
用 chosen_algorithm 用既定过程生成公私密钥对, 参考 IANA COSE Algorithms registry [IANA-COSE-ALGS-REG] 的算法。如生成失败则返回null。
-
令 bbk_and_algorithm 为二元组 (bbk, chosen_algorithm)。
-
令 bbk_id 为:
-
字节数组初始化:
-
令 bbk_id 长度为32。
-
调用
getRandomValues(bbk_id)。
-
-
从实现定义key生成过程的密钥对句柄序列化得到的字节数组。后续要用该字节数组从加密API检索对应的密钥。
注意: 许多加密API返回标识符、句柄或密钥包装(而非直接返回私钥及公钥),如私钥在安全元件中时只能用标识符/句柄/包装密钥调用API。
-
-
写入 keypair_map[bbk_id] = bbk_and_algorithm。
-
返回 (bbk_and_algorithm, bbk_id)。
-
规范可说明优先选用硬件存储算法(按顺序),其次软件存储算法。暂时Chrome每个平台只支持一种硬件算法。详细讨论见 Secure Payment Confirmation issue #288(涉及BBK存储类型、允许范围及是否暴露给依赖方)。
6.2. 绑定密钥对
要在给定含密钥对标识字节数组 bbk_id 和 credential_id 时 绑定密钥对,可能返回失败:
注意:将浏览器绑定密钥标识存储到 browser_bound_map 中,对应具体的 Credential ID(即passkey标识)。
-
写入 browser_bound_map[credential_id] = bbk_id。如遇
InvalidStateError、TypeError或QuotaExceededError则返回失败。注意:底层文件系统操作可能抛错(如
write(buffer, options))。 返回false则本次交易不会包含BBK,依赖方也无法拿到BBK。后续断言会尝试新建密钥对。
6.3. 检索密钥对
在给定 credential_id 字节数组和
PublicKeyCredentialParameters
组成的 allowed_algorithms 列表时,
获取或创建浏览器绑定密钥,返回包含 密钥对及 COSEAlgorithmIdentifier
的二元组,方法如下:
注意:找出已有对应 Credential ID 的密钥对或新建并返回。
-
如 browser_bound_map[credential_id] 存在
-
令 bbk_id = browser_bound_map[credential_id]。
-
令 bbk_and_algorithm = keypair_map[bbk_id]。
-
-
如 browser_bound_map[credential_id] 不 存在
-
返回 bbk_and_algorithm。
6.4. 获取浏览器绑定公钥
在给定密钥对和 COSEAlgorithmIdentifier
组成的二元组
bbk_and_algorithm时 获取浏览器绑定公钥,返回字节数组:
-
令 bbk = bbk_and_algorithm[0]。
-
令 algorithm = bbk_and_algorithm[1]。
-
根据 algorithm 的既定操作获取 bbk 的公钥为 public_key。
-
令 encoded_public_key 为 public_key 的 COSE_Key 编码。参见 WebAuthn credentialPublicKey。
-
返回 encoded_public_key。
6.5. 客户端数据签名
在给定密钥对和 COSEAlgorithmIdentifier
的二元组 bbk_and_algorithm,以及字节数组
client_data_json 时,生成浏览器绑定签名,返回字节数组:
注意:用 浏览器绑定密钥的私钥对 CollectedClientData
(含 CollectedClientAdditionalPaymentData
或 CollectedClientAdditionalPaymentRegistrationData)进行签名。
-
令 bbk = bbk_and_algorithm[0]。
-
令 algorithm = bbk_and_algorithm[1]。
-
用 algorithm 与 bbk 的私钥对 client_data_json 执行签名操作,得 signature。参见 IANA COSE Algorithms registry [IANA-COSE-ALGS-REG]。
注意:返回的是用 bbk 的私钥对 client_data_json 进行的密码学签名。
-
返回 signature。
7. 公共数据结构
以下数据结构在注册与认证之间共享。
7.1. PaymentCredentialInstrument
字典
dictionary PaymentCredentialInstrument {required USVString ;displayName required USVString ;icon boolean =iconMustBeShown true ;USVString ; };details
The PaymentCredentialInstrument
字典包含要向用户展示并与交易详情一并签名的信息。它包含下列成员:
displayName-
展示给用户的支付工具名称。
注意:关于
displayName的国际化讨论,请参见 § 14 国际化考虑。 icon-
支付工具图标的 URL。
注意:该
iconURL 可以是互联网上可访问服务器上的图片(例如https://bank.example/card.png),也可以通过 Data URL [RFC2397] 直接编码图标数据。在这两种类型中,Data URL 对于 Relying Party 有若干好处:它们可以提升可靠性(例如图标托管服务器不可用时),也能增强验证,因为 Relying Party 在被签名的CollectedClientAdditionalPaymentData结构中具有对浏览器展示内容的密码学证据(即图标 URL 被签名)。注意:参见相关的 无障碍考虑。
iconMustBeShown-
指示指定图标是否必须被成功获取并展示以使请求成功。
details-
可选的额外细节字符串,用于向用户展示支付工具的补充信息。
注意:关于
details的国际化讨论,请参见 § 14 国际化考虑。
7.2.
PaymentEntityLogo 字典
dictionary PaymentEntityLogo {required USVString ;url required USVString ; };label
The PaymentEntityLogo
字典包含描述为本次交易提供便利的支付实体的 logo 的信息。它包含下列成员:
url-
logo 的 URL。
注意:该
url可以是互联网上的图片(例如https://bank.com/logo.png),也可以通过 Data URL [RFC2397] 直接编码图像数据。相较之下,Data URL 对 Relying Party 有若干好处:可提升可靠性(例如 logo 托管服务器不可用时),并能增强验证,因为 Relying Party 在被签名的CollectedClientAdditionalPaymentData结构中具有对浏览器展示内容的密码学证据(即 logo URL 被签名)。 label-
logo 的描述性标签。用户代理可以(但不必)向用户显示此标签(见 § 4.9 显示交易确认界面),并应将其用于无障碍用途(例如在描述该 logo 的界面时由屏幕阅读器朗读)。
8. 权限策略集成
本规范使用来自 [payment-request] 的 "payment"
policy-identifier 字符串,
用于根据 PaymentRequest
构造函数控制对 SPC 认证的访问。
为与该规范的早期版本向后兼容,Credential
Management
Credential Type Registry 已扩展,添加 "payment"
policy-identifier 字符串,
作为 type public-key 的另一种 Create Permissions
Policy。未来版本的规范可能会弃用该行为。
注意:实际进行权限策略评估的算法由 [CREDENTIAL-MANAGEMENT-1] 指定。原因是这类策略评估需要在能访问 当前设置对象 时进行。[[Create]](origin, options, sameOriginWithAncestors)
和 [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)
这些 内部方法 并不具备该访问权限,
因为它们被(由 [CREDENTIAL-MANAGEMENT-1] 中指定的算法)并行调用(参见 并行)。
9. SPC 依赖方操作
9.1. 验证认证断言
为对 Secure Payment Confirmation 执行一次 认证流程,依赖方 必须按下列步骤进行:
-
令 credential 为从 Secure Payment Confirmation 支付处理器 成功调用中由 SPC 调用者 返回的
PublicKeyCredential。注意:由于 SPC 的设计支持 商户对认证的控制,发起 SPC 的实体可能并非依赖方。此第一步假定 SPC 调用者已将通过 SPC 获得的凭证返回给 依赖方。
-
按照 WebAuthn 中第 3–21 步执行验证,但作如下更改:
-
在第 11 步,验证 C["
type"] 的值为字符串payment.get。 -
在第 12 步,验证 C["
challenge"] 的值等于依赖方提供给 SPC 调用者 的 challenge 的 base64url 编码。 -
在第 13 步,验证 C["
origin"] 的值与依赖方期望 SPC 被调用的来源匹配。 -
在第 13 步之后,插入下列步骤:
-
验证 C["
payment"]["payeeOrigin"] 的值(若有)与应当显示给用户的收款方来源匹配。 -
验证 C["
payment"]["paymentEntitiesLogos"] 是应当展示给用户的 logo 列表的严格有序子集(若有)。注意:用户代理可以不展示所有 logo,但在
CollectedClientAdditionalPaymentData中不得包含未向用户展示的 logo。 -
验证 C["
payment"]["instrument"] 的值与应当展示给用户的支付工具详情匹配。
10. 用户代理自动化
为支持用户代理自动化和网站测试,本文档定义了下列 [WebDriver2] 扩展命令。感兴趣的方还应参考 WebAuthn 中的等价自动化章节。
10.1. 设置 SPC 交易模式
设置 SPC 交易模式 WebDriver 扩展命令 指示用户代理将 Secure Payment Confirmation 置于一种模式, 在该模式下会自动模拟用户接受或拒绝 交易确认界面。
当前活动的 交易自动化模式 跟踪 SPC 当前启用的自动化模式。默认值为 "none"。
| HTTP 方法 | URI 模板 |
|---|---|
| POST | /session/{session id}/secure-payment-confirmation/set-mode
|
远端步骤(remote end steps)如下:
-
如果 parameters 不是 JSON 对象,返回一个带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。
-
令 mode 为从 parameters 获取名为
"mode"的属性的结果(参见 getting a property)。 -
如果 mode 为 undefined 或不是 "
autoAccept"、"autoChooseToAuthAnotherWay"、"autoReject" 或 "autoOptOut" 之一,返回带有 WebDriver 错误代码 invalid argument 的 WebDriver 错误。 -
将 当前交易自动化模式 设置为 mode。
-
以 success 返回,数据为
null。
11. 安全注意事项
由于本规范建立在 WebAuthn 之上,WebAuthn 的安全注意事项 适用。本小节列出 Secure Payment Confirmation 特有的安全注意事项,即本规范相对 WebAuthn 的区别之处。
11.1. 跨源认证流程
Secure Payment Confirmation 与 WebAuthn 的一个重大不同点是允许第三方使用为另一 依赖方创建的凭证来发起认证流程,并将断言返回给第三方。此特性可能使 依赖方 面临登录和支付类攻击,下文讨论了这些风险。
11.1.1. 登录攻击
由于为 Secure Payment Confirmation 创建的凭证同时也是有效的 WebAuthn 凭证,依赖方可能会希望对同一用户将同一凭证用于登录和支付。这会带来一种潜在攻击,如果依赖方未谨慎验证它所接收的断言,攻击者或可利用该途径。
攻击流程如下:
-
用户访问
attacker.example,该站点为或冒充为商户网站。 -
attacker.example从relyingparty.example获得了该用户的凭证,可能是合法获得或从relyingparty.example或其他共享凭证的实体处窃取而来。 -
attacker.example发起 SPC 认证,且用户同意该交易(该交易可能合法也可能不合法)。 -
attacker.example将从 API 调用中获得的支付断言发送到relyingparty.example的登录端点,例如向https://relyingparty.example/login发送 POST。 -
relyingparty.example使用有缺陷的断言验证代码,仅校验签名但未验证必要字段(见下文),于是认为登录尝试合法。 -
relyingparty.example向attacker.example返回登录 cookie 等。relyingparty.example上的用户账户因此被攻破。
依赖方 可以用两种方式防范此类攻击。
其一,依赖方必须始终按照正确的断言验证步骤来校验断言——针对登录使用 WebAuthn 登录验证步骤,针对 SPC 使用 SPC 支付验证步骤。尤其下列字段可用于检测凭证的不当使用:
-
CollectedClientData["type"] — 登录为 "webauthn.get",SPC 为 "payment.get"。 -
CollectedClientData["challenge"] — 该值应由依赖方服务器在发起 WebAuthn 或 SPC 前向站点提供,且在验证时应核对为先前提供的、适当的期望值。 -
CollectedClientData["origin"] — 如为跨源 SPC,该值将包含调用者的 origin(例如上例中的attacker.example)。
其二,依赖方可以考虑将其支付凭证与登录凭证分开管理。如果采用此策略,依赖方应仅在子域(例如 https//payment.relyingparty.example)上为 Secure
Payment Confirmation 注册凭证,并在数据库中将支付凭证与登录凭证分开保存。
注意:按目前文本,Secure Payment Confirmation 规范允许任何 WebAuthn 凭证参与 SPC 认证。然而现实实现中并非如此,当前实现仅允许带有 payment
扩展的凭证参与 SPC 认证;未来规范可能会更新以反映这一点。
在当前实现与规范中,带有 payment
扩展创建的凭证,若依赖方愿意,可用于登录。这一行为预计不会改变。
11.1.2. 支付攻击
除非 Secure Payment Confirmation 断言是正在进行的线上交易的一部分,否则其实用性极低。
有多种机制可以防止一种攻击:恶意第三方不是试图劫持用户账户,而是使用(合法或非法获得的)Secure Payment Confirmation 凭证发起未授权付款:
-
当攻击者发起 SPC 时,用户代理会向用户展示清楚列明交易详情(包括收款方和金额)的界面。在这种情形下,用户很可能会“取消”。
-
如果用户确实同意了交易并完成随后 WebAuthn 的认证流程,攻击者将获得一个针对该 Relying Party 的已签名 SPC 断言。
-
如果该 Relying Party 并未预期此交易,它将拒绝该断言。
-
如果该 Relying Party 的确在等待交易,它将检测到至少下列之一并拒绝断言:
-
错误的
CollectedClientData["challenge"],若攻击者试图与有效正在进行的付款争用(race)时会出现。 -
错误的
CollectedClientData["origin"],若攻击者试图处于用户与有效商户站点之间并转发断言时会出现。
-
11.2. 商户提供的认证数据
银行可以且应该通过验证其收到的认证断言来防止欺骗,以确保证断言与商户提供的交易详情一致。
这是因为本规范的第三方认证流程的一个后果是:即便在有效交易中(即 Relying Party 所期望的交易),第三方也会提供展示给用户的交易详情:
-
交易金额与货币
-
支付工具名称与图标
-
收款方名称与来源
这可能导致欺骗攻击,即商户向用户展示不正确的数据。例如,商户可能在后端告诉银行它正在发起一笔 100 美元的购买,但传给 SPC API 的却是 1 美元(因此向用户展示的是 1 美元的交易以供核验)。或者商户可能提供正确的交易详情,但传递的 Secure Payment Confirmation 凭证并不符合 Relying Party 的期望。
实际上,Secure Payment Confirmation 使击败此类攻击比当前网络上的情况更容易做到。如今在线支付中,银行不得不信任商户在结账流程中向用户展示了正确金额(任何欺诈发现通常发生在支付之后,当用户查看对账单时)。
11.3. 攻击者生成的 浏览器绑定密钥
Relying Party(例如银行)可以且应该通过验证包含 BBK 公钥的认证断言来防范攻击者生成的 BBK,并在遇到签名无效的密码文本时忽略该 BBK 公钥。虽然会存在两个签名:一个来自 SPC Credential,另一个来自 BBK,但断言应使用 passkey(以及 BBK)一并验证。BBK 提供的是额外签名,而不是替代 passkey 签名的机制。
攻击者冒充商户可能尝试用其控制对应私钥的另一个 BBK 公钥替换原有公钥。随后,该攻击者再冒充用户访问商户站点,并在商户调用 SPC 时使用攻击者的私钥签署 SPC 密文。攻击者由此击败了 BBK 的设备绑定。
然而,此攻击不可行:
-
当攻击者替换 BBK 时:Relying Party 在使用 passkey 公钥验证包含 BBK 公钥的
CollectedClientData时会检测到签名错误。Relying Party 应拒绝该交易并将该 BBK 公钥视为不可信。 -
当攻击者试图冒充用户时:Relying Party 在使用 passkey 公钥验证时会检测到签名错误。Relying Party 应继续将该 BBK 公钥视为不可信。
11.4. 缺乏用户激活要求
如果用户代理如§ 4.3 修改用户激活要求所述不要求用户激活,则应考虑一些额外的安全缓解措施。不要求用户激活会增加垃圾信息和点击劫持攻击的风险,因为这允许在用户并未立即与页面交互的情况下发起 Secure Payment Confirmation 流程。
为减轻垃圾信息问题,用户代理可以在达到某个阈值后决定强制要求用户激活,例如当用户在当前页面已被展示过一次未启用用户激活的 Secure Payment Confirmation 流程后。为缓解点击劫持攻击,用户代理可以在对话框刚显示后的一段时间内忽略点击。
另一个相关的缓解存在于 PaymentRequest.show():Payment
Request API 要求文档可见,因此 SPC 不能从后台标签页、最小化窗口或其他类似隐藏情形触发。
12. 隐私考虑
由于本规范基于 WebAuthn,适用WebAuthn 的隐私考虑。下列小节列出 Secure Payment Confirmation 相对于 WebAuthn 的特有隐私考虑。
12.1. 探测凭证 ID
根据 WebAuthn 关于认证流程隐私的部分,Secure Payment Confirmation 的实现者必须确保恶意调用者(现在可能甚至不是 Relying Party)无法区分以下两种情况:
-
凭证不可用。
-
凭证可用,但用户不同意使用它。
如果上述情形可被区分,则会泄露信息,恶意 Relying Party 可以通过探测哪些凭证可用来识别用户。
在 Secure Payment Confirmation 中,这一风险通过始终展示交易确认界面并在以下两种情况下都返回相同错误(即 "NotAllowedError"
DOMException)来缓解:既无 SPC
Credential 可用,或有 SPC Credential 可用但用户选择不使用它。
12.2. 关联不同的支付工具
如果 Relying Party 在多个支付工具间为同一用户使用相同凭证,商户可能因此将本来无法关联的支付工具信息进行关联。也就是说,在用户 U 使用支付工具 P1 与 P2 进行的两笔不同交易中(无论是在同一商户 M,还是在两个串通的商户 M1 与 M2),商户现在可能能判断 P1 与 P2 属于同一用户。
对于许多当前的在线支付流程,这可能不是重要风险,因为用户通常会提供足以用于关联的信息(例如姓名、电子邮件、送货地址)。
然而,如果未来广泛采用包含更少识别信息的支付方法(例如令牌化),生态系统相关方应采取措施保护用户隐私。例如:
-
支付系统可能制定规则,限制第三方存储凭证 ID 或 BBK 公钥的行为。
-
当 Relying Party 将多个支付工具关联到单个 SPC 凭证时,可能选择不将该凭证 ID 共享给其他方。在这种情况下,Relying Party 仍可在第一方或第三方上下文中使用该 SPC 凭证本身来认证用户。
-
Relying Party(例如银行)可以允许用户为每个支付工具注册独立的 SPC 凭证。这样做不会阻止该 Relying Party 在内部将这些账户进行关联。
12.3. 凭证 ID 作为追踪向量
即便针对单一支付工具,由 Relying Party 返回的凭证 ID 也可能被恶意实体作为强跨站标识用于追踪。然而,商户要从 Relying Party 获取这些凭证 ID,已经需要商户向 Relying Party 提供一个同样强的标识(例如信用卡号)。
12.4. 浏览器绑定密钥作为追踪向量
BBK 公钥仅在每次 SPC 支付断言中返回(以及在初次第一方创建 SPC Credential 时返回一次)。但要获取 BBK,商户必须先从 Relying Party 获取凭证 ID 才能发起 SPC,且用户必须使用其 passkey 对交易进行认证。由于访问 BBK 公钥需要先访问凭证 ID,BBK 公钥并未增加额外的追踪能力。
12.5. 通过 securePaymentConfirmationAvailability 导致的指纹识别
securePaymentConfirmationAvailability
API 可能带来指纹识别风险,因为它可以静默返回导致 SPC 在特定帧不可用的具体原因。这些原因不会被认为泄露重大信息,但仍应予以考虑:
-
unavailable-feature-not-enabled: 存在一定的指纹识别风险,取决于用户代理在何种情形下决定提供或不提供 Secure Payment Confirmation。鼓励用户代理对所有用户(若实现此规范)或至少对足够大的用户群体提供 Secure Payment Confirmation,以避免(额外的)指纹识别风险。例如,用户代理可在特定操作系统上对所有用户启用 SPC,而在其他操作系统上不启用——这将把指纹识别风险限制到不超过用户代理字符串已暴露的信息量。 -
unavailable-no-permission-policy: 无(额外)指纹识别风险,因为 "payment" 权限策略已经可以通过尝试构造PaymentRequest对象静默检测到(若权限策略未启用,构造将抛出错误)。 -
unavailable-no-user-verifying-platform-authenticator: 相较于已有的isUserVerifyingPlatformAuthenticatorAvailableAPI 无(额外)指纹识别风险。
除上述考虑外,本规范允许用户代理在知悉具体原因时选择返回 unavailable-unknown-reason,
以保护用户隐私。例如当用户代理检测到当前帧已访问其他存在指纹识别风险的 API 时,可能会采取此举。
12.6. 用户选择退出
API 选项 showOptOut
告知用户代理为用户提供一种方式,让用户表明其希望退出依赖方存储信息。当用户触发此退出时,会向调用方返回 OptOutError,以指示用户的退出意图。随后由调用方决定如何响应该退出,例如清除为用户存储的支付信息。
实现者必须确保返回 OptOutError
不会泄露用户存在凭证但未完成认证的信息。可用与§ 12.1 探测凭证 ID
相似的办法缓解,例如在找不到凭证匹配时,仍在过渡性 UX 中为用户提供选择退出的机会。
这并非用于删除浏览器数据或凭证的机制——其目的是由开发者通过用户代理提示用户选择退出。用户代理应向用户明确说明,例如给出说明文字:“该提供者可能已存储有关您支付方式的信息,您可以请求删除这些信息。”
13. 无障碍考虑
用户代理将 icon
与 displayName
一并渲染。依赖方应通过提供足够的信息在 displayName
(例如若图标代表银行,则在 displayName
中包含银行名称)来确保图标呈现的可访问性。
实现本规范的用户代理应同时遵循 WebAuthn 的无障碍考虑 与 PaymentRequest 的无障碍考虑。
14. 国际化考虑
API 的调用方应通过 locale
成员表达交易对话框所期望的区域设置以及任何可显示字符串的本地化。一般而言,该成员应与请求发起页面的本地化一致(例如通过查询触发请求的按钮的 lang 属性)。
本规范目前尚未包含机制让调用方将语言或方向元数据与它们传入 API 的可显示字符串(例如 displayName)关联起来。
在此期间,API 的调用方应当:
-
在提供时,确保
locale的值与可显示字符串的语言保持一致。 -
确保字符串内的方向变化在显示时能被正确渲染(参见“How to use Unicode controls for bidi text”以及“Inline changes to base direction”以获取更多信息)。
实现(及其他尝试显示这些值的进程)应在将可显示字符串插入用户界面时应用 双向隔离(bidi isolation)。当已知方向时应设置方向,否则默认采用 first-strong(“auto”)。
15. IANA 考量
本节将以下列出的扩展标识符添加到由 [IANA-WebAuthn-Registries] 管理的 IANA“WebAuthn Extension Identifiers”登记表中(该登记表由 [RFC8809] 建立)。
-
WebAuthn 扩展标识符:payment
-
描述:此扩展支持 Secure Payment Confirmation API 所定义的下列功能: (1) 允许在跨域 iframe 中创建凭证;(2) 允许除 Relying Party 之外的方代表 Relying Party 使用该凭证执行认证流程;(3) 允许浏览器识别并缓存 Secure Payment Confirmation 凭证。关于 SPC 与 Web Authentication 在重要方面的差异,请参见特别是 § 11 安全注意事项 与 § 12 隐私考虑
-
规范文档:本规范的 § 5 WebAuthn Extension - "payment"
-
注释:登记遵循与 Web Authentication Working Group 在 2023-05-03 讨论 的一致意见。