瞭解如何最佳化簡訊動態密碼表單,並改善使用者體驗。
常見的方法是要求使用者提供透過簡訊傳送的動態密碼 (動態密碼),這是確認使用者電話號碼的常見方式。簡訊動態密碼有幾種用途:
- 雙重驗證。除了使用者名稱和密碼外,簡訊動態密碼還能做為高強度信號,表明帳戶為接收簡訊動態密碼的使用者所有。
- 驗證電話號碼。部分服務會使用電話號碼做為使用者的主要 ID。在這類服務中,使用者可以輸入電話號碼和透過簡訊收到的動態密碼,藉此驗證身分。有時會與 PIN 碼結合,以構成雙重驗證。
- 帳戶救援。當使用者失去帳戶存取權時,您需要能夠找方法復原帳戶。傳送電子郵件至註冊的電子郵件地址,或發送簡訊動態密碼給對方的電話號碼,是常見的帳戶救援方式。
- 付款確認:基於安全考量,在付款系統中,部分銀行或信用卡發卡機構會要求付款人進行額外驗證。簡訊動態密碼通常用於這類用途。
本文針對上述用途說明建構簡訊動態密碼表單的最佳做法。
檢查清單
如要讓簡訊動態密碼提供最佳使用者體驗,請按照下列步驟操作:
- 請搭配使用
<input>
元素和:type="text"
inputmode="numeric"
autocomplete="one-time-code"
- 請將
@BOUND_DOMAIN #OTP_CODE
設為動態密碼簡訊的最後一行。 - 使用 WebOTP API。
使用 <input>
元素
使用含有 <input>
元素的表單是最重要的最佳做法,因為這項功能適用於所有瀏覽器。即使這篇文章提供的其他建議無法在某些瀏覽器中運作,使用者仍可自行輸入並提交動態密碼。
<form action="/verify-otp" method="POST">
<input type="text"
inputmode="numeric"
autocomplete="one-time-code"
pattern="\d{6}"
required>
</form>
以下幾個提案,可確保輸入欄位能充分運用瀏覽器功能。
type="text"
動態密碼通常為 5 或 6 位數字,因此在輸入欄位使用 type="number"
看起來會像是直覺,因為這樣會將行動鍵盤變更為僅限數字。我們不建議這麼做,因為瀏覽器預期輸入欄位是可計數的數字,而非一系列的多個數字,這可能會導致非預期的行為。使用 type="number"
會導致輸入欄位旁邊顯示上下按鈕,按下這些按鈕可增加或減少數字,且可能會移除前面的零。
請改用 type="text"
。這並不會將行動裝置鍵盤轉換為數字,但也沒有問題,因為接下來有關使用 inputmode="numeric"
的提示也能執行該工作。
inputmode="numeric"
使用 inputmode="numeric"
將行動裝置鍵盤變更為僅限數字。
部分網站會在 OTP 輸入欄位使用 type="tel"
,因為這麼做也會在聚焦當下將行動裝置鍵盤切換為數字 (包括 *
和 #
)。這個駭客攻擊過去曾在未廣泛支援 inputmode="numeric"
時使用。自 Firefox 開始支援 inputmode="numeric"
後,您就無需使用語意上不正確的 type="tel"
入侵。
autocomplete="one-time-code"
autocomplete
屬性可讓開發人員指定瀏覽器提供自動完成協助所需的權限,並將欄位中預期資訊類型告知瀏覽器。
如果使用 autocomplete="one-time-code"
,每當使用者在表單開啟時收到簡訊,作業系統就會以啟發式方式剖析簡訊中的動態密碼,鍵盤也會建議使用者輸入的動態密碼。這種方法僅適用於 iOS、iPadOS 和 macOS 上的 Safari 12 以上版本,但我們強烈建議您採用,因為這樣可以輕鬆改善這些平台上的簡訊動態密碼體驗。
autocomplete="one-time-code"
可改善使用者體驗,但您可以確保簡訊符合來源傳送的訊息格式,也可以採取其他做法。
設定簡訊文字格式
啟用來源繫結的一次性代碼 (透過簡訊傳送的一次性代碼),改善進入動態密碼的使用者體驗。
這個格式規則很簡單:使用接收者網域在簡訊前面加上 @
,然後在簡訊開頭加上 #
的動態密碼。
例如:
Your OTP is 123456
@web-otp.glitch.me #123456
使用動態密碼訊息的標準格式可簡化從這類訊息擷取程式碼,不僅更加可靠。將動態密碼 (OTP) 代碼與網站建立關聯後,會比較難誘騙使用者向惡意網站提供程式碼。
使用這種格式有幾項好處:
- 系統會將動態密碼繫結至網域。如果使用者所在的網域不是簡訊中指定的網域,系統就不會顯示動態密碼建議。這種做法也可降低網路釣魚攻擊和潛在帳戶盜用的風險。
- 瀏覽器現在可以穩定地擷取 OTP,不必依賴神秘和不穩定的經驗法則來處理。
網站使用 autocomplete="one-time-code"
時,iOS 14 以上版本的 Safari 會依照上述規則建議使用 OTP。
這種簡訊格式也對 Safari 以外的瀏覽器有益。此外,Android 上的 Chrome、Opera 和 Vivaldi 也支援透過 WebOTP API (但不透過 autocomplete="one-time-code"
) 使用來源繫結的一次性代碼規則。
使用 WebOTP API
WebOTP API 可讓您存取簡訊中收到的動態密碼。使用 otp
類型 (OTPCredential
) 呼叫 navigator.credentials.get()
,其中 transport
包含 sms
,網站會等待符合來源限定的一次性代碼的簡訊,並由使用者授予存取權。將動態密碼傳送至 JavaScript 後,網站就能以表單或 POST 的方式,將動態密碼直接發布至伺服器。
navigator.credentials.get({
otp: {transport:['sms']}
})
.then(otp => input.value = otp.code);
如要進一步瞭解如何使用 WebOTP API,請參閱「使用 WebOTP API 驗證網路上的電話號碼」或複製及貼上下列程式碼片段。(確認 <form>
元素已正確設定 action
和 method
屬性)。
// Feature detection
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e => {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
// Cancel the WebOTP API if the form is submitted manually.
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e => {
// Cancel the WebOTP API.
ac.abort();
});
}
// Invoke the WebOTP API
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp => {
input.value = otp.code;
// Automatically submit the form when an OTP is obtained.
if (form) form.submit();
}).catch(err => {
console.log(err);
});
});
}
相片來源:Jason Leung 在 Unsplash 上。