安全付款确认

W3C 候选推荐草案,

关于本文档的更多详情
本版本:
https://www.w3.org/TR/2025/CRD-secure-payment-confirmation-20251209/
最新发布版本:
https://www.w3.org/TR/secure-payment-confirmation/
编辑草稿:
https://w3c.github.io/secure-payment-confirmation/
历史版本:
历史记录:
https://www.w3.org/standards/history/secure-payment-confirmation/
实现报告:
https://wpt.fyi/results/secure-payment-confirmation
反馈:
GitHub
规范内反馈
编辑:
(谷歌)
前编辑:
(谷歌)
贡献者:
Ian Jacobs (W3C)
Nick Burris (谷歌)
测试套件:
https://wpt.fyi/results/secure-payment-confirmation/

摘要

安全付款确认 (SPC) 是一种网页 API,旨在支持在支付交易中简化认证流程。它设计用于跨商家扩展认证,适用于多种认证协议,并能生成用户已确认交易详情的加密凭证。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 出版物和本技术报告最新版本请参见 W3C 标准与草案索引

本文档由 Web 支付工作组 按照 推荐流程 发布为候选推荐草案。

自上一个候选推荐快照以来的变更,请参阅 GitHub 变更日志

作为候选推荐发布并不意味着 W3C 及其成员的认可。候选推荐草案整合了工作组计划在后续候选推荐快照中包含的前一版本变更。

这是草稿文档,可能随时被更新、替换或废止。引用本文档为正式资料不适宜,仅作为正在进行的工作。

要使本规范晋升为提案推荐,我们必须展示在用户代理中有两个独立、可互操作的实现;详见相关 实现报告

该候选推荐预计不早于2023年8月1日晋升为提案推荐。

Web 支付工作组维护一个 问题列表

作为候选推荐发布并不意味着 W3C 及其成员的认可。候选推荐草案整合了工作组计划在后续候选推荐快照中包含的前一版本变更。

本文档由依照 W3C 专利政策 运作的团体制作。W3C 公布了该团体相关的 专利披露公开列表;该页面还包含专利披露说明。任何个人实际知晓某专利且认为其包含必要权利要求,须按W3C 专利政策第6条披露相关信息。

本文档受 2025年8月18日 W3C 流程文件 管辖。

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 字段中存储待验证的支付信息。这会带来以下问题:

  1. 这是对 challenge 字段的误用(其原本用于防止重放攻击)。

  2. 没有相关的规范,每家银行都需自行设计支付信息在 challenge 中的格式及编码方式,增加部署难度并加剧割裂。

  3. 某些监管要求必须证明用户确实已看见并同意该支付信息。单用 [webauthn-3] 不提供此类展示:challenge 字段内信息无任何规范的用户体验指引。

上述局限促成了以下安全支付确认(SPC)行为:

  1. challenge 字段仅用于防止重放攻击,与普通 [webauthn-3] 相同。

  2. SPC 对支付信息指定了统一格式,有助于通用验证代码和测试套件开发。

  3. SPC 保证用户代理以网站(或恶意注入 JS 代码)无法绕过的方式向用户展示支付信息。

    注意:当下支付生态中的银行等主体通过 TLS、iframe 等 Web 功能足以信任浏览器环境下的支付。目前规范旨在进一步提升 Web 支付的安全性与易用性。

1.1.2. 商户对认证的控制

商户希望减少结账过程中的用户流失,尤其是降低认证阻力。依赖方(如银行)一般使用 [webauthn-3] 进行用户认证时,通常是在 iframe 内完成。但商户更希望主导用户认证过程体验,同时也能让 依赖方验证认证结果。

此类局限推动了安全支付确认(SPC)下的新行为:

上述特性带来的额外好处是依赖方自身不必再开发认证前端体验,支付服务商可能会为商户开发此类体验。

注意:希望自定义认证体验的依赖方仍可在 iframe 中用 SPC 完成。

1.1.3. 设备绑定的密码学证据

在支付行业,设备持有信号是重要的二要素。WebAuthn 支持同步密钥,单一凭证可跨多设备使用(参见 Web Authentication § 1.2.1 消费者多设备凭证)。虽然同步提升了登录体验,有声音担忧仅靠同步密钥不能满足某些监管环境下“设备持有”要求。

上述担忧推动本规范引入用户代理生成的辅助 公私钥对,私钥仅保存在一个设备内且仅由该设备使用。此类密钥及其在 SPC 中的应用称为 浏览器绑定密钥

1.2. API 示例使用场景

本节举例介绍安全支付确认常见场景及 API 使用代码,实际应用不限于以下流程。

1.2.1. 结账过程中的注册

这是首次流程,用户在某商户结账时,发卡银行会新建并存储一个凭证。

  1. 用户访问 merchant.example,选购商品后进入结账流程,录入支付工具信息,并确认付款(例如点击“支付”按钮)。

  2. 商户与发卡银行进行带外通信(例如使用其他协议)。发卡银行请求用户验证,并提供银行控制的 URL 供商户在 iframe 内打开。

  3. 商户在 bank.example 打开一个带 allow 属性值为 "publickey-credentials-create" 的 iframe。

  4. iframe 内,发卡银行通过传统方式(如短信验证码)确认用户身份,随后邀请用户注册 SPC 认证以便未来支付。

  5. 用户同意(例如点击银行界面的“注册”按钮),银行在 iframe 内运行如下代码。

  6. 用户进行 WebAuthn 注册流程,新凭证创建后返回给银行,银行服务端与用户和支付工具关联存储。

  7. 验证流程完成后银行 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. 商户网站认证

当用户已注册凭证,在进行交易且发卡银行和商户希望使用安全支付确认时,流程如下。

  1. 用户访问 merchant.example,选购商品后进入结账流程,输入支付工具信息,确认付款(如点击“支付”按钮)。

  2. 商户与支付工具发卡银行进行带外通信(如使用其他协议)。发卡银行请求用户验证,同时告知商户已支持 SPC,并提供调用 API 所需信息。包括挑战值和与该用户及支付工具绑定的所有凭证ID。

  3. 商户运行下方示例代码。

  4. 用户在 SPC 界面同意支付信息,并完成后续 WebAuthn 认证流程。签名密文返回给商户(包含 AuthenticationExtensionsPaymentOutputs 的浏览器绑定密钥输出)。

  5. 商户将签名密文带外发送给发卡银行。银行验证密文,并确认用户有效、所显示的支付信息,以及用户已经同意本次交易。银行授权交易,商户完成结账流程。银行保存 浏览器绑定密钥的公钥, 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 需提供 namedisplayName, 但根据user成员定义,实现不要求后续认证流程展示。截止2023年10月,name展示更一致。开发者需关注实现动态。

4. 认证 - 安全支付确认支付方式

要通过安全支付确认进行付款认证,本规范定义了:

  1. 一个 支付处理器,即 安全支付确认支付处理器,用来处理认证指定支付的请求。

  2. 该支付处理器的标准化支付方式标识符为 "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. 处理支付方式:[子步骤1-3 遗略]

    1. seenPMIs包含 "secure-payment-confirmation" 且 seenPMIs 长度大于1,则抛出RangeError异常。

4.3. 修改用户激活要求

PaymentRequest.show() 方法步骤中,修改步骤2和3:

  1. 相关全局对象request 不具有 瞬时激活,用户代理可选择:

    1. 返回一个被拒绝的 promise,异常类型为"SecurityError" DOMException

  2. 否则,消耗用户激活(即消费关联全局对象的激活状态)。

注意: 允许用户代理无需用户激活,可支持重定向认证流程(如重定向后无用户激活)。安全相关见 § 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<> 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 一同或单独提供。

payeeOrigin

本次SPC调用收款人来源(如商户)。可选,或与 payeeName 一同或单独提供。

paymentEntitiesLogos

代表本次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", 以保护用户隐私或无法完成某步骤时。

  1. 如用户代理不支持安全支付确认,或支持但通过某种机制被禁用,则返回 "unavailable-feature-not-enabled"。

  2. document 未启用 "payment" 权限策略,则返回 "unavailable-no-permission-policy"。

  3. 如无用户验证平台认证器 可用,则返回 "unavailable-no-user-verifying-platform-authenticator"。

  4. 如有任何其他原因致使安全支付确认在 document 下无法工作,则返回 "unavailable-unknown-reason"。

  5. 返回 "available"。

此 API 允许开发者如下检查是否需要发起SPC流程:

const spcAvailable =
    PaymentRequest &&
    PaymentRequest.securePaymentConfirmationAvailability &&
    await PaymentRequest.securePaymentConfirmationAvailability() === 'available';

注意: 建议使用静态securePaymentConfirmationAvailability 方法做SPC特性检测,而不是在已构建的 PaymentRequest 实例上调用canMakePayment

注意: 本API涉及隐私问题,详见 § 12.5 通过securePaymentConfirmationAvailability指纹识别

4.7. 验证支付方式数据的步骤

对于本支付方式,输入 PaymentRequest requestSecurePaymentConfirmationRequest data 所需的 验证支付方式数据的步骤如下:

测试
  1. 如果 data["credentialIds"] 为空, 抛出 RangeError

  2. 针对 data["credentialIds"] 中每个 id

    1. 如果 id 为空,则抛出 RangeError

  3. data["challenge"] 为 null 或 为空,则抛出 TypeError

  4. data["instrument"]["displayName"] 为空,则抛出 TypeError

  5. data["instrument"]["icon"] 为空,则抛出 TypeError

  6. 对 data["instrument"] ["icon"] 运行网址解析器。 若解析失败,抛出 TypeError

  7. data["instrument"]["details"] 有值但为空,则抛出 TypeError

  8. data["rpId"] 不是有效域名,则抛出 TypeError

  9. data["payeeName"] 和 data["payeeOrigin"] 均未提供, 则抛出 TypeError

  10. 如果 data["payeeName"] 和 data["payeeOrigin"] 有值但为空,则抛出 TypeError

  11. data["payeeOrigin"] 有值:

    1. parsedURL 为对 data["payeeOrigin"] 运行网址解析器的结果。

    2. parsedURL 解析失败,则抛出 TypeError

    3. parsedURLscheme 不为 "https",则抛出 TypeError

  12. data["paymentEntitiesLogos"] 有值且非空:

    1. 对每个 logodata["paymentEntitiesLogos"] 数组中:

      1. logo["url"] 为空,则抛出 TypeError

      2. logo["url"] 运行网址解析器。 若解析失败,则抛出 TypeError

      3. logo["label"] 为空,则抛出 TypeError

  13. data["locale"] 存在非空

    1. data["locale"] 中每个 tag

      1. tag 不是格式良好的 [BCP47] 语言标签,则抛出 TypeError

    注意:locale 与特定输入项绑定的语言或方向元数据不同,代表调用方请求的本地化体验而非对某个字符串值的断言。更多讨论见 § 14 国际化考虑

4.8. 检查能否进行支付的步骤

对于本支付方式,输入 SecurePaymentConfirmationRequest data 所需的 检查能否进行支付的步骤如下:

测试
  1. data["payeeOrigin"] 有值:

    1. parsedURL 为对 data["payeeOrigin"] 运行网址解析器的结果。

    2. 断言 parsedURL 不是失败。

    3. 断言 parsedURLscheme 为 "https"。

    注意:这些前置条件已在 验证支付方式数据的步骤进行过检查。

    1. data["payeeOrigin"] 设置为 parsedURLorigin序列化值。

  2. 拉取icon对应的图片资源,传递 «["src" → data["instrument"]["icon"]]» 作为 image;若拉取失败:

    1. data["instrument"]["iconMustBeShown"] 为 true,则返回 false

    2. 否则,将 data["instrument"]["icon"] 设为空字符串。

      注意:这样可让RP知晓指定icon未能展示,因输出instrument 的 icon 字段为空。

    注意:图片资源必须无论凭证是否匹配均要拉取,以防推测凭证是否存在。

  3. 用户代理可选地从 data["paymentEntitiesLogos"] 从后往前移除条目。

    注意:这样允许用户代理控制展示logo数量,并保持logo优先级排序的语义。

  4. data["paymentEntitiesLogos"] 中每个 logo

    1. 拉取logo的图片资源,传递 «["src" → logo["url"]]» 作为 image,并解码结果。

    2. 如拉取或解码失败,将 logo["url"] 设为空字符串。

      注意:这样让RP知晓指定logo未能展示,因输出paymentEntitiesLogos 的对应logo条目的 url 字段为空。

    注意:Logo图片必须无论凭证是否匹配均要拉取,以防推测凭证是否存在。

  5. data["credentialIds"] 中每个 id

    1. 运行静默判断凭证是否可用于当前设备的步骤,传递 data["rpId"] 和 id。 如结果为 false,则从 data["credentialIds"] 移除 id

    2. data["rpId"] 不等于 requestorigin, 则运行静默判断SPC凭证是否已启用第三方使用步骤,传递 data["rpId"] 和 id。如结果为 false,则从 data["credentialIds"] 移除 id

  6. 返回 true

4.9. 显示交易确认界面

当调用 PaymentRequest.show() 并选中 安全支付确认支付处理器(该算法第19-24步),用户代理必须向用户展示界面,允许用户选择是否及如何继续。

4.9.1. 向用户展示的信息

为避免限制用户代理实现选择,本规范不强制要求特定界面。但为使 依赖方能信任 CollectedClientPaymentData 所含信息, 用户代理必须确保下列信息被传递给用户,并收集到用户对认证的同意:

用户代理可利用 locale 信息(如有)来展示与网站一致的本地化语言和格式界面。

showOptOuttrue,用户代理必须让用户能选择对该 依赖方 退出流程。

测试

4.9.2. 交易确认界面结果

用户代理必须允许用户指明是否及如何继续的选项:

用户希望继续付款,并用 SPC凭证 认证

对交互中的 PaymentRequest 执行 用户接受支付请求算法

用户希望继续付款,但因 data["credentialIds"] 为空无法使用 SPC凭证,或者主动选择不用 SPC凭证

运行下列步骤:

  1. data["credentialIds"] 为空列表。

    注意:此举将使 PaymentRequest.show() 被拒绝(NotAllowedError DOMException),参考 响应支付请求的步骤

  2. 对交互中的 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 requestSecurePaymentConfirmationRequest data,其 响应支付请求的步骤为:

注意:仅当用户接受交易确认界面时才会执行本步骤,由 用户接受支付请求算法调用。

  1. data["credentialIds"] 为空, 抛出 "NotAllowedError" DOMException。 这在用户无法或不愿用SPC认证时保护认证流程隐私。

    注意:此处抛出异常,会导致 PaymentRequest.show() 被拒绝(NotAllowedError DOMException)。

  2. topOriginrequest顶级origin

  3. 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"]

  4. extensions 为新 AuthenticationExtensionsClientInputs 字典,payment 成员为 payment,其它成员从 data["extensions"] 设置。

  5. publicKeyOpts 为新 PublicKeyCredentialRequestOptions 字典,其字段为:

    challenge

    data["challenge"]

    timeout

    data["timeout"]

    rpId

    data["rpId"]

    userVerification

    required

    extensions

    extensions

    注意:本算法将"userVerification"设为"required",是因Chrome初始实现仅支持该值。后续限制可能变化。工作组欢迎提出支持其它值(如"preferred"或"discouraged")的使用场景。

  6. data["credentialIds"] 中每个 id

    1. descriptor 为新 PublicKeyCredentialDescriptor 字典,其字段为:

      type

      public-key

      id

      id

      transports

      长度为1的序列,唯一成员为 internal

    2. descriptor 添加到 publicKeyOpts["allowCredentials"]。

  7. outputCredential 为执行 请求凭证算法(传递«["publicKey" → publicKeyOpts]»)的结果。

    注意:Chrome最初实现不会将 data.credentialIds 全部传入请求凭证算法,仅传入已匹配当前设备的一个。

    注意:此操作会触发 [webauthn-3]Get 行为。

  8. 返回 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):

  1. 第3步后插入以下步骤:

  2. 第13步前(创建 CollectedClientData 前)。

    测试
    1. bbk_allowed_algorithmsbrowserBoundPubKeyCredParams

    2. browserBoundPubKeyCredParams 为空,令 bbk_allowed_algorithmsPublicKeyCredentialCreationOptions.pubKeyCredParams

    3. 令 (bbk_and_algorithm, bbk_id) 为用 bbk_allowed_algorithms 创建密钥对的结果。

    4. 如 (bbk_and_algorithm, bbk_id) 为 null,跳过与 bbk_and_algorithmbbk_public_key 有关的步骤。

    5. bbk_public_key 为用 bbk_and_algorithm 获取浏览器绑定公钥的结果。

  3. 第13步,将创建 CollectedClientData 换成 CollectedClientPaymentData,包含以下字段:

    payment

    初始化为 CollectedClientAdditionalPaymentRegistrationData,字段有:

    browserBoundPublicKey

    bbk_public_key,COSE_Key 编码的 公钥

    其它字段

    其余字段按原13步操作。

  4. 第22步,判断“有认证器指示成功”时返回 pubKeyCred 前:

    1. bbk_idpubKeyCred.[[identifier]] 绑定密钥对。如失败,返回 UnknownError

    2. payment_outputsAuthenticationExtensionsPaymentOutputs,包含:

      browserBoundSignature

      初始化为 BrowserBoundSignature,字段有:

      signature

      bbk_and_algorithm 与 create credential 第14步的 clientDataJson 生成浏览器绑定签名 的结果。

    3. [[clientExtensionsResults]]["payment"] 设为 payment_outputs

客户端扩展处理(认证

当用 AuthenticationExtensionsPaymentInputs extension_inputs 断言时:

  1. 如不在 "secure-payment-confirmation" 支付处理器内,返回 "NotAllowedError" DOMException。

    测试

    注意:防止网站不通过交易界面绕过SPC能力。

  2. [[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors) 期间:

    1. 跳过6.1步(比较 options.rpId 与 effectiveDomain)。

    测试

    注意:由此可支持跨域认证流程,详见 § 1.1.2 商户对认证的控制

    1. 第10步前(创建 CollectedClientData 前)。

      1. allowed_algorithmsSecurePaymentConfirmationRequest.browserBoundPubKeyCredParams

      2. bbk_and_algorithm 为用 credential_idallowed_algorithms 获取或创建浏览器绑定密钥的结果。

    2. 第10步,将创建 CollectedClientData 换成 CollectedClientPaymentData,包含:

      1. type 设为 "payment.get"

      2. 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 获取浏览器绑定公钥结果。否则不设置。

      3. 其余字段按原10步设置。

      测试
    3. “有认证器指示成功”时,在第2步设置 [[clientExtensionsResults]]

      1. payment_outputsAuthenticationExtensionsPaymentOutputs,字段有:

        browserBoundSignature

        bbk_and_algorithm 非 null,则初始化 BrowserBoundSignature,字段有:

        signature

        bbk_and_algorithm 与 create credential 第14步的 clientDataJson 生成浏览器绑定签名 的结果。

      2. 设置 [[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。如同时存在,rprpId 必须相同。

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 KeyStoreApple CryptoKitWindows Cryptography API: Next Generation

浏览器绑定密钥存储包含如下内容:

browser_bound_map

Credential ID 到密钥对标识符的映射。

keypair_map

从字节数组(密钥对标识符)到由公私密钥对和算法标识符 COSEAlgorithmIdentifier 组成的二元组映射。

注意: 用户代理可调用加密API以实现类似 keypair_map 功能,则该部分工作可委托给加密API。

6.1. 创建密钥对

要在给定 PublicKeyCredentialParameters, allowed_algorithms创建密钥对,返回包含密钥对和其 COSEAlgorithmIdentifier 及密钥对标识字节数组的二元组,请按如下步骤执行:

注意:根据允许算法或默认列表生成密钥对

  1. 如果 allowed_algorithms 为空, 则使用如下默认列表:

  2. 移除 allowed_algorithms 中类型不是 PublicKeyCredential 的条目。

  3. 移除用户代理不支持的 allowed_algorithms 条目。

    注意: 不同平台用户代理支持的加密算法不同。

  4. allowed_algorithms长度为零则返回null。

    注意:此时用户代理不会输出任何浏览器绑定内容。

  5. allowed_algorithms长度大于零:

    1. chosen_algorithmallowed_algorithms[0]。

    2. chosen_algorithm 用既定过程生成公私密钥对, 参考 IANA COSE Algorithms registry [IANA-COSE-ALGS-REG] 的算法。如生成失败则返回null。

    3. bbk_and_algorithm 为二元组 (bbk, chosen_algorithm)。

    4. bbk_id 为:

      1. 字节数组初始化:

        1. bbk_id 长度为32。

        2. 调用 getRandomValues(bbk_id)。

      2. 从实现定义key生成过程的密钥对句柄序列化得到的字节数组。后续要用该字节数组从加密API检索对应的密钥。

      注意: 许多加密API返回标识符、句柄或密钥包装(而非直接返回私钥及公钥),如私钥在安全元件中时只能用标识符/句柄/包装密钥调用API。

    5. 写入 keypair_map[bbk_id] = bbk_and_algorithm

    6. 返回 (bbk_and_algorithm, bbk_id)。

规范可说明优先选用硬件存储算法(按顺序),其次软件存储算法。暂时Chrome每个平台只支持一种硬件算法。详细讨论见 Secure Payment Confirmation issue #288(涉及BBK存储类型、允许范围及是否暴露给依赖方)。

6.2. 绑定密钥对

要在给定含密钥对标识字节数组 bbk_idcredential_id绑定密钥对,可能返回失败:

注意:将浏览器绑定密钥标识存储到 browser_bound_map 中,对应具体的 Credential ID(即passkey标识)。

  1. 写入 browser_bound_map[credential_id] = bbk_id。如遇 InvalidStateErrorTypeErrorQuotaExceededError 则返回失败。

    注意:底层文件系统操作可能抛错(如 write(buffer, options))。 返回false则本次交易不会包含BBK,依赖方也无法拿到BBK。后续断言会尝试新建密钥对。

6.3. 检索密钥对

在给定 credential_id 字节数组和 PublicKeyCredentialParameters 组成的 allowed_algorithms 列表时, 获取或创建浏览器绑定密钥,返回包含 密钥对COSEAlgorithmIdentifier 的二元组,方法如下:

注意:找出已有对应 Credential ID 的密钥对或新建并返回。

  1. browser_bound_map[credential_id] 存在

    1. bbk_id = browser_bound_map[credential_id]。

    2. bbk_and_algorithm = keypair_map[bbk_id]。

  2. browser_bound_map[credential_id] 不 存在

    1. 令 (new_bbk_and_algorithm, bbk_id) = 创建密钥对(allowed_algorithms)。

    2. binding_result = 绑定密钥对(bbk_id, credential_id)。如返回失败,bbk_and_algorithm = null。

    3. binding_result 非失败,bbk_and_algorithm = new_bbk_and_algorithm

  3. 返回 bbk_and_algorithm

6.4. 获取浏览器绑定公钥

在给定密钥对和 COSEAlgorithmIdentifier 组成的二元组 bbk_and_algorithm获取浏览器绑定公钥,返回字节数组:

注意:获取 浏览器绑定密钥的编码公钥

  1. bbk = bbk_and_algorithm[0]。

  2. algorithm = bbk_and_algorithm[1]。

  3. 根据 algorithm 的既定操作获取 bbk公钥public_key

  4. encoded_public_keypublic_key 的 COSE_Key 编码。参见 WebAuthn credentialPublicKey

  5. 返回 encoded_public_key

6.5. 客户端数据签名

在给定密钥对和 COSEAlgorithmIdentifier 的二元组 bbk_and_algorithm,以及字节数组 client_data_json 时,生成浏览器绑定签名,返回字节数组:

注意:浏览器绑定密钥私钥CollectedClientData (含 CollectedClientAdditionalPaymentDataCollectedClientAdditionalPaymentRegistrationData)进行签名。

  1. bbk = bbk_and_algorithm[0]。

  2. algorithm = bbk_and_algorithm[1]。

  3. algorithmbbk私钥client_data_json 执行签名操作,得 signature。参见 IANA COSE Algorithms registry [IANA-COSE-ALGS-REG]

    注意:返回的是用 bbk私钥client_data_json 进行的密码学签名。

  4. 返回 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。

注意:icon URL 可以是互联网上可访问服务器上的图片(例如 https://bank.example/card.png),也可以通过 Data URL [RFC2397] 直接编码图标数据。在这两种类型中,Data URL 对于 Relying Party 有若干好处:它们可以提升可靠性(例如图标托管服务器不可用时),也能增强验证,因为 Relying Party 在被签名的 CollectedClientAdditionalPaymentData 结构中具有对浏览器展示内容的密码学证据(即图标 URL 被签名)。

注意:参见相关的 无障碍考虑

iconMustBeShown

指示指定图标是否必须被成功获取并展示以使请求成功。

details

可选的额外细节字符串,用于向用户展示支付工具的补充信息。

注意:关于 details 的国际化讨论,请参见 § 14 国际化考虑

7.2. 字典

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 执行一次 认证流程依赖方 必须按下列步骤进行:

  1. credential 为从 Secure Payment Confirmation 支付处理器 成功调用中由 SPC 调用者 返回的 PublicKeyCredential

    注意:由于 SPC 的设计支持 商户对认证的控制,发起 SPC 的实体可能并非依赖方。此第一步假定 SPC 调用者已将通过 SPC 获得的凭证返回给 依赖方

  2. 按照 WebAuthn 中第 3–21 步执行验证,但作如下更改:

    1. 在第 5 步中,验证 credential.id 是否标识了 SPC 调用者依赖方 那里获取的某个公钥凭证。

    2. 在第 11 步,验证 C["type"] 的值为字符串 payment.get

    3. 在第 12 步,验证 C["challenge"] 的值等于依赖方提供给 SPC 调用者 的 challenge 的 base64url 编码。

    4. 在第 13 步,验证 C["origin"] 的值与依赖方期望 SPC 被调用的来源匹配。

    5. 在第 13 步之后,插入下列步骤:

      • 验证 C["payment"]["rpId"] 的值与依赖方的 origin 匹配。

      • 验证 C["payment"]["topOrigin"] 的值与依赖方期望的顶层 origin 匹配。

      • 验证 C["payment"]["payeeName"] 的值(若有)与应当显示给用户的收款方名称匹配。

      • 验证 C["payment"]["payeeOrigin"] 的值(若有)与应当显示给用户的收款方来源匹配。

      • 验证 C["payment"]["paymentEntitiesLogos"] 是应当展示给用户的 logo 列表的严格有序子集(若有)。

        注意:用户代理可以不展示所有 logo,但在 CollectedClientAdditionalPaymentData 中不得包含未向用户展示的 logo。

      • 验证 C["payment"]["total"] 的值与应当展示给用户的交易金额匹配。

      • 验证 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)如下:

  1. 如果 parameters 不是 JSON 对象,返回一个带有 WebDriver 错误代码 invalid argumentWebDriver 错误

  2. mode 为从 parameters 获取名为 "mode" 的属性的结果(参见 getting a property)。

  3. 如果 modeundefined 或不是 "autoAccept"、"autoChooseToAuthAnotherWay"、"autoReject" 或 "autoOptOut" 之一,返回带有 WebDriver 错误代码 invalid argumentWebDriver 错误

  4. 当前交易自动化模式 设置为 mode

  5. success 返回,数据为 null

11. 安全注意事项

由于本规范建立在 WebAuthn 之上,WebAuthn 的安全注意事项 适用。本小节列出 Secure Payment Confirmation 特有的安全注意事项,即本规范相对 WebAuthn 的区别之处。

11.1. 跨源认证流程

Secure Payment Confirmation 与 WebAuthn 的一个重大不同点是允许第三方使用为另一 依赖方创建的凭证来发起认证流程,并将断言返回给第三方。此特性可能使 依赖方 面临登录和支付类攻击,下文讨论了这些风险。

11.1.1. 登录攻击

由于为 Secure Payment Confirmation 创建的凭证同时也是有效的 WebAuthn 凭证,依赖方可能会希望对同一用户将同一凭证用于登录和支付。这会带来一种潜在攻击,如果依赖方未谨慎验证它所接收的断言,攻击者或可利用该途径。

攻击流程如下:

  1. 用户访问 attacker.example,该站点为或冒充为商户网站。

  2. attacker.examplerelyingparty.example 获得了该用户的凭证,可能是合法获得或从 relyingparty.example 或其他共享凭证的实体处窃取而来。

  3. attacker.example 发起 SPC 认证,且用户同意该交易(该交易可能合法也可能不合法)。

  4. attacker.example 将从 API 调用中获得的支付断言发送到 relyingparty.example 的登录端点,例如向 https://relyingparty.example/login 发送 POST。

  5. relyingparty.example 使用有缺陷的断言验证代码,仅校验签名但未验证必要字段(见下文),于是认为登录尝试合法。

  6. relyingparty.exampleattacker.example 返回登录 cookie 等。relyingparty.example 上的用户账户因此被攻破。

依赖方 可以用两种方式防范此类攻击。

其一,依赖方必须始终按照正确的断言验证步骤来校验断言——针对登录使用 WebAuthn 登录验证步骤,针对 SPC 使用 SPC 支付验证步骤。尤其下列字段可用于检测凭证的不当使用:

其二,依赖方可以考虑将其支付凭证与登录凭证分开管理。如果采用此策略,依赖方应仅在子域(例如 https//payment.relyingparty.example)上为 Secure Payment Confirmation 注册凭证,并在数据库中将支付凭证与登录凭证分开保存。

注意:按目前文本,Secure Payment Confirmation 规范允许任何 WebAuthn 凭证参与 SPC 认证。然而现实实现中并非如此,当前实现仅允许带有 payment 扩展的凭证参与 SPC 认证;未来规范可能会更新以反映这一点。

在当前实现与规范中,带有 payment 扩展创建的凭证,若依赖方愿意,可用于登录。这一行为预计不会改变。

11.1.2. 支付攻击

除非 Secure Payment Confirmation 断言是正在进行的线上交易的一部分,否则其实用性极低。

有多种机制可以防止一种攻击:恶意第三方不是试图劫持用户账户,而是使用(合法或非法获得的)Secure Payment Confirmation 凭证发起未授权付款:

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 的设备绑定。

然而,此攻击不可行:

  1. 当攻击者替换 BBK 时:Relying Party 在使用 passkey 公钥验证包含 BBK 公钥的 CollectedClientData 时会检测到签名错误。Relying Party 应拒绝该交易并将该 BBK 公钥视为不可信。

  2. 当攻击者试图冒充用户时: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 属于同一用户。

对于许多当前的在线支付流程,这可能不是重要风险,因为用户通常会提供足以用于关联的信息(例如姓名、电子邮件、送货地址)。

然而,如果未来广泛采用包含更少识别信息的支付方法(例如令牌化),生态系统相关方应采取措施保护用户隐私。例如:

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-unknown-reason, 以保护用户隐私。例如当用户代理检测到当前帧已访问其他存在指纹识别风险的 API 时,可能会采取此举。

12.6. 用户选择退出

API 选项 showOptOut 告知用户代理为用户提供一种方式,让用户表明其希望退出依赖方存储信息。当用户触发此退出时,会向调用方返回 OptOutError,以指示用户的退出意图。随后由调用方决定如何响应该退出,例如清除为用户存储的支付信息。

实现者必须确保返回 OptOutError 不会泄露用户存在凭证但未完成认证的信息。可用与§ 12.1 探测凭证 ID 相似的办法缓解,例如在找不到凭证匹配时,仍在过渡性 UX 中为用户提供选择退出的机会。

这并非用于删除浏览器数据或凭证的机制——其目的是由开发者通过用户代理提示用户选择退出。用户代理应向用户明确说明,例如给出说明文字:“该提供者可能已存储有关您支付方式的信息,您可以请求删除这些信息。”

13. 无障碍考虑

用户代理将 icondisplayName 一并渲染。依赖方应通过提供足够的信息在 displayName (例如若图标代表银行,则在 displayName 中包含银行名称)来确保图标呈现的可访问性。

实现本规范的用户代理应同时遵循 WebAuthn 的无障碍考虑PaymentRequest 的无障碍考虑

14. 国际化考虑

API 的调用方应通过 locale 成员表达交易对话框所期望的区域设置以及任何可显示字符串的本地化。一般而言,该成员应与请求发起页面的本地化一致(例如通过查询触发请求的按钮的 lang 属性)。

本规范目前尚未包含机制让调用方将语言或方向元数据与它们传入 API 的可显示字符串(例如 displayName)关联起来。

在此期间,API 的调用方应当:

实现(及其他尝试显示这些值的进程)应在将可显示字符串插入用户界面时应用 双向隔离(bidi isolation)。当已知方向时应设置方向,否则默认采用 first-strong(“auto”)。

15. IANA 考量

本节将以下列出的扩展标识符添加到由 [IANA-WebAuthn-Registries] 管理的 IANA“WebAuthn Extension Identifiers”登记表中(该登记表由 [RFC8809] 建立)。

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语相结合来表达。 本文档规范性部分中的关键词 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY” 和 “OPTIONAL” 应按照 RFC 2119 的说明进行解释。 但为了便于阅读,本规范未将这些词全部大写。

本规范的全部文本均为规范性内容, 除明确标记为非规范性、示例和注释的部分。[RFC2119]

本规范中的示例以 “for example” 等词引入, 或用 class="example" 与规范性文本分开, 如下所示:

这是一个信息性示例。

信息性注释以 “Note” 开头, 并用 class="note" 与规范性文本区分, 如下所示:

注意,这是一个信息性注释。

测试

与本规范内容相关的测试 可能记录在类似这样的“Tests”块中。 所有此类块都是非规范性的。


一致性算法

以命令式表述并作为算法一部分的要求(如 “strip any leading space characters” 或“return false and abort these steps”) 应结合引入该算法时所用关键词(“must”、“should”、“may”等)来解释其含义。

以算法或具体步骤表述的一致性要求可以用任何实现方式实现, 只要最终结果是等效的。 特别地,本规范中定义的算法旨在易于理解, 并不强调性能。 鼓励实现者进行优化。

索引

本规范定义的术语

引用中定义的术语

参考文献

规范性引用

[CREDENTIAL-MANAGEMENT-1]
Nina Satragno; Marcos Caceres. 凭证管理一级. 2025年10月28日. WD. URL: https://www.w3.org/TR/credential-management-1/
[DOM]
Anne van Kesteren. DOM 标准. 现行标准. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 语言规范. URL: https://tc39.es/ecma262/multipage/
[FETCH]
Anne van Kesteren. Fetch 标准. 现行标准. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML 标准. 现行标准. URL: https://html.spec.whatwg.org/multipage/
[I18N-GLOSSARY]
Richard Ishida; Addison Phillips. 国际化术语表. 2024年10月17日. 备注. URL: https://www.w3.org/TR/i18n-glossary/
[IANA-COSE-ALGS-REG]
IANA CBOR 对象签名和加密(COSE)算法注册表. URL: https://www.iana.org/assignments/cose/cose.xhtml#algorithms
[IANA-WebAuthn-Registries]
Web 身份认证注册表(WebAuthn). URL: https://www.rfc-editor.org/rfc/rfc8809.html
[IMAGE-RESOURCE]
Aaron Gustafson; Rayan Kanso; Marcos Caceres. 图像资源. 2021年6月4日. WD. URL: https://www.w3.org/TR/image-resource/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 现行标准. URL: https://infra.spec.whatwg.org/
[PAYMENT-METHOD-ID]
Marcos Caceres. 支付方式标识符. 2022年9月8日. REC. URL: https://www.w3.org/TR/payment-method-id/
[PAYMENT-REQUEST]
Marcos Caceres; Ian Jacobs; Stephen McGruer. 支付请求 API. 2025年9月30日. CRD. URL: https://www.w3.org/TR/payment-request/
[RFC2119]
S. Bradner. 用于指示要求级别的关键词. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC8809]
J. Hodges; G. Mandyam; M. Jones. Web 身份认证注册表(WebAuthn). 2020年8月. 信息性. URL: https://www.rfc-editor.org/rfc/rfc8809
[URL]
Anne van Kesteren. URL 标准. 现行标准. URL: https://url.spec.whatwg.org/
[WEBAUTHN-3]
Tim Cappalli; et al. Web 身份认证:公共密钥凭证访问 API - 第3级. 2025年1月27日. WD. URL: https://www.w3.org/TR/webauthn-3/
[WEBCRYPTO-2]
Daniel Huigens. Web 加密二级. 2025年4月22日. FPWD. URL: https://www.w3.org/TR/webcrypto-2/
[WEBDRIVER1]
Simon Stewart; David Burns. WebDriver. 2018年6月5日. REC. URL: https://www.w3.org/TR/webdriver1/
[WebDriver2]
Simon Stewart; David Burns. WebDriver. 2025年10月28日. WD. URL: https://www.w3.org/TR/webdriver2/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 现行标准. URL: https://webidl.spec.whatwg.org/

非规范性引用

[BCP47]
A. Phillips, Ed.; M. Davis, Ed.. 用于标识语言的标签. 2009年9月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc5646
[FS]
Austin Sullivan. 文件系统标准. 现行标准. URL: https://fs.spec.whatwg.org/
[RFC2397]
L. Masinter. “data” URL 方案. 1998年8月. 拟标准. URL: https://www.rfc-editor.org/rfc/rfc2397
[RFC4647]
A. Phillips, Ed.; M. Davis, Ed.. 语言标签匹配. 2006年9月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc4647
[WEBAUTHN-CONDITIONAL-UI]
WebAuthn 条件 UI 提案. URL: https://github.com/w3c/webauthn/issues/1545

IDL 索引

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;
};

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();
};

partial dictionary AuthenticationExtensionsClientInputs {
  AuthenticationExtensionsPaymentInputs payment;
};

dictionary AuthenticationExtensionsPaymentInputs {
  boolean isPayment;
  sequence<PublicKeyCredentialParameters> browserBoundPubKeyCredParams;

  // Only used for authentication.
  USVString rpId;
  USVString topOrigin;
  USVString payeeName;
  USVString payeeOrigin;
  sequence<PaymentEntityLogo> paymentEntitiesLogos;
  PaymentCurrencyAmount total;
  PaymentCredentialInstrument instrument;
};

partial dictionary AuthenticationExtensionsClientOutputs {
  AuthenticationExtensionsPaymentOutputs payment;
};

dictionary AuthenticationExtensionsPaymentOutputs {
  BrowserBoundSignature browserBoundSignature;
};

dictionary BrowserBoundSignature {
  required ArrayBuffer signature;
};

dictionary CollectedClientPaymentData : CollectedClientData {
    required (CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData) payment;
};

dictionary CollectedClientAdditionalPaymentData {
    required USVString rpId;
    required USVString topOrigin;
    USVString payeeName;
    USVString payeeOrigin;
    sequence<PaymentEntityLogo> paymentEntitiesLogos;
    required PaymentCurrencyAmount total;
    required PaymentCredentialInstrument instrument;
    USVString browserBoundPublicKey;
};

dictionary CollectedClientAdditionalPaymentRegistrationData {
    USVString browserBoundPublicKey;
};

dictionary PaymentCredentialInstrument {
    required USVString displayName;
    required USVString icon;
    boolean iconMustBeShown = true;
    USVString details;
};

dictionary PaymentEntityLogo {
    required USVString url;
    required USVString label;
};

问题索引

本规范当前版本每个 PaymentEntityLogo 仅支持单一 URL,因此直接复制和签名该数据结构即可表明用户看到的内容。未来版本可能会为每个 PaymentEntityLogo 增加多个 URL(例如原生支持暗黑模式)。如出现这种情况,规范需指明给 依赖方实际展示的是哪个 URL。
规范可以规定优先选择硬件存储的算法(按给定顺序),再选择软件存储的算法(同顺序)。目前此问题实际意义不大,因为 Chrome 计划每个平台仅支持一种硬件算法。参见 Secure Payment Confirmation 第288号议题,讨论了BBK的存储类型等,包括应允许哪些存储类型、是否应将存储类型暴露给依赖方等。