協助使用者透過簡訊收到的 OTP
什麼是 WebOTP API?
現今,全球大多數人都擁有行動裝置,開發人員通常會使用電話號碼做為服務使用者的 ID。
驗證電話號碼的方法有很多種,但最常見的方式之一就是透過簡訊傳送隨機產生的動態密碼。將此代碼傳回開發人員的伺服器,即可證明您控制電話號碼。
這個概念已在許多情境中部署,用於達成以下目標:
- 電話號碼做為使用者的識別資訊。註冊新服務時,有些網站會要求提供電話號碼,而非電子郵件地址,並將電話號碼用做帳戶 ID。
- 兩步驟驗證:網站在登入時,除了密碼或其他知識因素外,還會要求輸入透過簡訊傳送的一次性驗證碼,以提供額外的安全性。
- 付款確認。使用者付款時,要求透過簡訊傳送一次性驗證碼,有助於驗證使用者的意圖。
目前的程序會讓使用者感到不便。在簡訊中找出 OTP,然後複製並貼到表單中,這項操作相當繁瑣,會降低關鍵使用者歷程的轉換率。許多全球大型開發人員一直希望能簡化這項作業,Android 有專門用於此用途的 API。iOS 和 Safari 也是如此。
WebOTP API 可讓應用程式接收與應用程式網域綁定的特殊格式訊息。您可以透過程式輔助方式從簡訊中取得 OTP,並更輕鬆地為使用者驗證電話號碼。
實例觀摩
假設使用者想透過網站驗證電話號碼。網站會透過簡訊傳送簡訊給使用者,使用者輸入訊息中的動態密碼,即可驗證電話號碼的擁有權。
使用 WebOTP API 後,使用者只要輕觸一下即可完成這些步驟,如影片所示。收到簡訊後,系統會彈出底部功能表,提示使用者驗證電話號碼。點選底部功能表的「驗證」按鈕後,瀏覽器會將 OTP 貼到表單中,並提交表單,而使用者不必按下「繼續」。
下圖顯示整個程序的流程圖。
請試用示範。系統不會要求你提供電話號碼,也不會傳送簡訊到你的裝置,但你可以透過複製示範中顯示的文字,從其他裝置傳送簡訊。這是因為使用 WebOTP API 時,傳送者是誰並不重要。
- 在 Android 裝置上使用 Chrome 84 以上版本前往 https://web-otp.glitch.me。
- 使用其他手機傳送以下簡訊給你的手機。
Your OTP is: 123456.
@web-otp.glitch.me #12345
你是否已收到簡訊,並在輸入區域看到輸入驗證碼的提示? 這就是 WebOTP API 對使用者而言的運作方式。
使用 WebOTP API 包含三個部分:
- 正確註解的
<input>
標記 - 網頁應用程式中的 JavaScript
- 透過簡訊傳送的格式化訊息文字。
我會先介紹 <input>
標記。
為 <input>
標記加註
WebOTP 本身無需任何 HTML 註解即可運作,但為了跨瀏覽器的相容性,強烈建議您在預期使用者輸入 OTP 的 <input>
標記中,新增 autocomplete="one-time-code"
。
這樣一來,當 Safari 14 以上版本收到格式符合「格式化簡訊訊息」所述的簡訊時,即使不支援 WebOTP,也能建議使用者在收到簡訊時,透過 OTP 自動填入 <input>
欄位。
HTML
<form>
<input autocomplete="one-time-code" required/>
<input type="submit">
</form>
使用 WebOTP API
由於 WebOTP 很簡單,只要複製並貼上以下程式碼即可完成。我會逐步說明發生的情況。
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}
特徵偵測
功能偵測與許多其他 API 相同。監聽 DOMContentLoaded
事件會等待 DOM 樹狀結構準備好供查詢。
JavaScript
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
…
const form = input.closest('form');
…
});
}
處理動態密碼
WebOTP API 本身相當簡單。使用 navigator.credentials.get()
取得 OTP。WebOTP 會在該方法中新增 otp
選項。它只有一個屬性:transport
,其值必須是包含字串 'sms'
的陣列。
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
…
這會在簡訊到達時觸發瀏覽器的權限流程。如果授予權限,則傳回的承諾會以 OTPCredential
物件解析。
取得的 OTPCredential
物件內容
{
code: "123456" // Obtained OTP
type: "otp" // `type` is always "otp"
}
接下來,將 OTP 值傳遞至 <input>
欄位。直接提交表單,即可省略要求使用者輕觸按鈕的步驟。
JavaScript
…
navigator.credentials.get({
otp: { transport:['sms'] }
…
}).then(otp => {
input.value = otp.code;
if (form) form.submit();
}).catch(err => {
console.error(err);
});
…
中止訊息
如果使用者手動輸入 OTP 並提交表單,您可以使用 options
物件中的 AbortController
例項,取消 get()
呼叫。
JavaScript
…
const ac = new AbortController();
…
if (form) {
form.addEventListener('submit', e => {
ac.abort();
});
}
…
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
…
設定簡訊格式
API 本身看起來應該相當簡單,但在使用前,您需要先瞭解幾件事。訊息必須在呼叫 navigator.credentials.get()
後傳送,且必須在呼叫 get()
的裝置上接收。最後,訊息必須遵循下列格式:
- 訊息開頭為可供人類閱讀的文字 (選用),其中包含四到十個字元的英數字元字串,且至少包含一個數字,最後一行則留給網址和 OTP。
- 叫用 API 的網站網址中,網域部分的前面必須加上
@
。 - 網址必須包含井字號 ('
#
') 和隨後的 OTP。
例如:
Your OTP is: 123456.
@www.example.com #123456
以下是錯誤示例:
格式錯誤的 SMS 文字範例 | 為何這麼做會失敗 |
---|---|
Here is your code for @example.com #123456 |
@ 應是最後一行的第一個字元。 |
Your code for @example.com is #123456 |
@ 應是最後一行的首個字元。 |
Your verification code is 123456 @example.com\t#123456 |
@host 和 #code 之間應有一個空格。 |
Your verification code is 123456 @example.com #123456 |
@host 和 #code 之間應有一個空格。 |
Your verification code is 123456 @ftp://example.com #123456 |
不得加入網址配置。 |
Your verification code is 123456 @https://example.com #123456 |
不得加入網址配置。 |
Your verification code is 123456 @example.com:8080 #123456 |
不得包含通訊埠。 |
Your verification code is 123456 @example.com/foobar #123456 |
請勿加入路徑。 |
Your verification code is 123456 @example .com #123456 |
網域中不得有空白字元。 |
Your verification code is 123456 @domain-forbiden-chars-#%/:<>?@[] #123456 |
網域中不得包含禁用字元。 |
@example.com #123456 Mambo Jumbo |
@host 和 #code 應為最後一行。 |
@example.com #123456 App hash #oudf08lkjsdf834 |
@host 和 #code 應為最後一行。 |
Your verification code is 123456 @example.com 123456 |
缺少 # 。 |
Your verification code is 123456 example.com #123456 |
缺少 @ 。 |
Hi mom, did you receive my last text |
缺少 @ 和 # 。 |
示範
請透過以下範例試試各種訊息:https://web-otp.glitch.me
您也可以分支並建立自己的版本:https://glitch.com/edit/#!/web-otp。
從跨來源 iframe 使用 WebOTP
將簡訊 OTP 輸入跨來源 iframe 通常用於付款確認,尤其是使用 3D Secure 時。WebOTP API 採用通用格式支援跨來源 iframe,可提供綁定至巢狀來源的 OTP。例如:
- 使用者造訪
shop.example
,並使用信用卡購買一雙鞋子。 - 輸入信用卡號碼後,整合式付款服務供應商會在 iframe 中顯示來自
bank.example
的表單,要求使用者驗證電話號碼,以便快速結帳。 bank.example
會傳送含有 OTP 的簡訊給使用者,方便他們輸入驗證碼來驗證身分。
如要在跨來源 iframe 中使用 WebOTP API,您必須執行以下兩項操作:
- 在簡訊文字訊息中註解頂層框架來源和 iframe 來源。
- 設定權限政策,允許跨來源 iframe 直接從使用者接收 OTP。
您可以在 https://web-otp-iframe-demo.stackblitz.io 試用這個範例。
在簡訊中標註繫結來源
當 WebOTP API 從 iframe 中呼叫時,簡訊必須包含頂層框架來源,前面加上 @
,接著是 OTP,前面加上 #
,最後一行則是 iframe 來源,前面加上 @
。
Your verification code is 123456
@shop.example #123456 @bank.exmple
設定權限政策
如要在跨來源 iframe 中使用 WebOTP,嵌入者必須透過 otp-credentials 權限政策授予此 API 存取權,以免發生非預期行為。一般來說,有兩種方法可以達成這個目標:
透過 HTTP 標頭:
Permissions-Policy: otp-credentials=(self "https://bank.example")
透過 iframe allow
屬性:
<iframe src="https://bank.example/…" allow="otp-credentials"></iframe>
請參閱其他範例 ,進一步瞭解如何指定權限政策。
在電腦上使用 WebOTP
在 Chrome 中,WebOTP 支援監聽其他裝置收到的 SMS,協助使用者在電腦上完成電話號碼驗證。
使用者必須在 Chrome 桌面版和 Chrome Android 版中登入相同的 Google 帳戶,才能使用這項功能。
開發人員只需在電腦版網站上導入 WebOTP API,就像在行動版網站上導入一樣,但不需要使用任何特殊技巧。
如要進一步瞭解如何使用 WebOTP API 在電腦上驗證電話號碼,請參閱這篇文章。
常見問題
即使我傳送的訊息格式正確,對話方塊也不會顯示。發生了什麼事?
測試 API 時,請注意以下幾點:
- 如果收件者的聯絡資訊中包含寄件者的電話號碼,由於底層 SMS User Consent API 的設計,系統不會觸發這個 API。
- 如果您在 Android 裝置上使用工作資料夾,而 WebOTP 無法運作,請改為在個人資料夾 (即您接收簡訊的資料夾) 中安裝及使用 Chrome。
請檢查格式,確認簡訊格式是否正確。
這個 API 是否與不同瀏覽器相容?
Chromium 和 WebKit 同意採用 簡訊格式,Apple 也宣布 Safari 將從 iOS 14 和 macOS Big Sur 開始支援這項格式。雖然 Safari 不支援 WebOTP JavaScript API,但如果您使用 autocomplete=["one-time-code"]
為 input
元素加上註解,當簡訊符合格式時,預設鍵盤會自動建議您輸入 OTP。
使用 SMS 做為驗證方式是否安全?
雖然透過簡訊傳送 OTP 可在首次提供電話號碼時驗證號碼,但由於電話號碼可能遭到盜用或回收,因此透過簡訊驗證電話號碼時,請務必謹慎使用。WebOTP 是方便的重新驗證和復原機制,但服務應搭配其他因素 (例如知識挑戰) 使用,或是使用 Web Authentication API 進行強式驗證。
如何回報 Chrome 實作項目中的錯誤?
你是否發現 Chrome 實作項目有錯誤?
- 請前往 crbug.com 提交錯誤。請盡可能提供詳細資訊,提供重現問題的簡單操作說明,並將「Component」設為
Blink>WebOTP
。
我可以如何協助改善這項功能?
您打算使用 WebOTP API 嗎?您的公開支持有助於我們決定功能的優先順序,並向其他瀏覽器供應商顯示支援這些功能的重要性。使用主題標記 #WebOTP
發送推文給 @ChromiumDev,告訴我們你在何處使用這項功能,以及使用方式。