WebOTP API

安全上下文:此功能仅在安全上下文(HTTPS)中可用,在部分或所有支持的浏览器中可用。

WebOTP API为 Web 应用程序提供了一种简化的用户体验,用于在使用电话号码作为登录因子时验证电话号码是否属于用户。WebOTP 是凭据管理 API的扩展。

验证通过两步过程完成

  1. 应用程序客户端请求一次性密码(OTP),该密码是从应用程序服务器发送的格式特殊的 SMS 消息中获取的。
  2. JavaScript 用于将 OTP 输入应用程序客户端上的验证表单,并将其提交回服务器以验证它是否与最初在 SMS 中发送的内容匹配。

概念和用法

电话号码通常用作识别应用程序用户的一种方式。通常使用 SMS 来验证号码是否属于用户。SMS 通常包含 OTP,用户需要将 OTP 复制粘贴到应用程序中的表单中以验证他们是否拥有该号码。这是一种有点笨拙的用户体验。

OTP 使用案例包括

  • 通过使用电话号码作为额外因子来提高登录安全性(例如,用于双重身份验证 (2FA) 或多重身份验证 (MFA))。
  • 验证敏感操作,例如付款。

WebOTP API 允许 Web 应用程序在用户提供同意后(大多数原生平台都有等效的 API)通过从 SMS 中复制 OTP 并将其自动传递给应用程序来加快此验证过程。

请注意,OTP 与发送域绑定。这是一个有用的安全约束,用于验证 OTP 是否来自正确的来源,这可以减轻日常重新认证期间的网络钓鱼攻击风险。

SMS OTP 的安全问题

SMS OTP 对于验证电话号码很有用,并且使用 SMS 进行第二因子验证肯定比没有第二因子验证要好。在某些地区,电子邮件地址和身份验证器等其他标识符的使用并不广泛,因此 SMS OTP 非常普遍。

但是,SMS 并不安全。攻击者可以伪造 SMS 并劫持用户的电话号码。运营商可以在帐户关闭后将电话号码回收给新用户。

因此,建议您尽可能使用更强大的身份验证形式,例如使用Web 身份验证 API 的基于密码和安全密钥或通行密钥的解决方案。

WebOTP API 如何工作?

该过程的工作原理如下

  1. 在需要电话号码验证的点,应用程序客户端将要求用户将他们的电话号码输入表单,然后将其提交给应用程序服务器。
  2. 然后,应用程序客户端使用 otp 选项调用navigator.credentials.get(),指定 transport 类型为 "sms"。这会触发从底层系统请求 OTP,该系统的来源将是来自应用程序服务器的格式特殊的 SMS 消息(包含 OTP 和应用程序的域)。get() 调用是Promise 驱动的,并等待 SMS 消息被接收。
  3. 应用程序服务器将 SMS 消息发送到指定的电话号码。这必须在步骤 2 发生后立即完成。
  4. 当 SMS 在设备上接收时,如果它包含应用程序的域,浏览器会询问用户是否同意检索/使用 OTP。例如,Chrome 会显示一个对话框,要求他们提供从 SMS 中检索 OTP 的权限;其他浏览器可能以不同的方式处理它。如果他们同意,get() 调用将完成并返回一个包含 OTP 的OTPCredential 对象。
  5. 然后,您可以按任何您希望的方式使用 OTP。典型的用法是将其设置为应用程序客户端上验证表单的值,然后提交表单,使整个过程尽可能无缝。
  6. 然后,应用程序服务器将验证发送回它的 OTP 是否与它最初在 SMS 中发送的内容匹配,如果匹配,则完成该过程(例如,登录用户)。

SMS 消息格式

典型的 SMS 消息如下所示

Your verification code is 123456.

@www.example.com #123456
  • 第一行和第二空行是可选的,用于人类可读性。
  • 最后一行是必需的。如果存在其他行,它必须是最后一行,并且必须包含
    • 调用 API 的网站的 URL 的域名部分,前面是 @
    • 后面是一个空格。
    • 后面是 OTP,前面是井号 (#)。

注意:提供的域名值不能包含 URL 模式、端口或上面未显示的其他 URL 功能。

如果 get() 方法由嵌入在<iframe> 中的第三方网站调用,则 SMS 结构应为

Your verification code is 123456.

@top-level.example.com #123456 @embedded.com

在这种情况下,最后一行必须包含

  • 顶级域的域名部分,前面是 @
  • 后面是一个空格。
  • 后面是 OTP,前面是井号 (#)。
  • 后面是一个空格。
  • 后面是嵌入域的域名部分,前面是 @

控制对 API 的访问

可以使用权限策略 控制 WebOTP 的可用性,指定otp-credentials 指令。此指令的默认允许列表值为 "self",这意味着默认情况下,这些方法可以在顶级文档上下文中使用。

您可以指定一个指令,允许在特定跨域域(即,在<iframe> 内)使用 WebOTP,例如

http
Permissions-Policy: otp-credentials=(self "https://embedded.com")

或者,您也可以在 <iframe> 上直接指定它,例如

html
<iframe src="https://embedded.com/..." allow="otp-credentials"> ... </iframe>

注意:如果策略禁止使用 WebOTP get(),则由它返回的promise 将使用 SecurityError DOMException 拒绝。

接口

OTPCredential

当 WebOTP get() 调用完成时返回;包含一个包含检索到的 OTP 的 code 属性。

对其他接口的扩展

CredentialsContainer.get()otp 选项

使用 otp 选项调用 get() 会指示用户代理尝试从底层系统的 SMS 应用程序检索 OTP。

示例

在此示例中,当 SMS 消息到达并且用户授予权限时,将返回一个包含 OTP 的OTPCredential 对象。然后,此密码将预先填充到验证表单字段中,并提交表单。

使用手机试用此演示.

表单字段包含一个autocomplete 属性,其值为 one-time-code。这对于 WebOTP API 的正常工作不是必需的,但值得包含。因此,即使 WebOTP API 在 Safari 中没有得到完全支持,Safari 也会在接收到格式正确的 SMS 时提示用户使用 OTP 自动填充此字段。

html
<input type="text" autocomplete="one-time-code" inputmode="numeric" />

JavaScript 如下所示

js
// Detect feature support via OTPCredential availability
if ("OTPCredential" in window) {
  window.addEventListener("DOMContentLoaded", (e) => {
    const input = document.querySelector('input[autocomplete="one-time-code"]');
    if (!input) return;
    // Set up an AbortController to use with the OTP request
    const ac = new AbortController();
    const form = input.closest("form");
    if (form) {
      // Abort the OTP request if the user attempts to submit the form manually
      form.addEventListener("submit", (e) => {
        ac.abort();
      });
    }
    // Request the OTP via get()
    navigator.credentials
      .get({
        otp: { transport: ["sms"] },
        signal: ac.signal,
      })
      .then((otp) => {
        // When the OTP is received by the app client, enter it into the form
        // input and submit the form automatically
        input.value = otp.code;
        if (form) form.submit();
      })
      .catch((err) => {
        console.error(err);
      });
  });
}

AbortController 的另一个好用途是在一定时间后取消 get() 请求

js
setTimeout(() => {
  // abort after 30 seconds
  ac.abort();
}, 30 * 1000);

如果用户分心或导航到其他地方,最好取消请求,这样他们就不会被呈现与他们不再相关的权限提示。

规范

规范
WebOTP API

另请参阅