使用者驗證深入解析

本文將討論 WebAuthn 中的 userVerification,以及在建立或驗證密碼金鑰時指定 userVerification 後,瀏覽器會出現的行為。

WebAuthn 中的「使用者驗證」是什麼?

密碼金鑰採用公開金鑰密碼編譯技術,建立密碼金鑰時,系統會產生公開/私密金鑰組,私密金鑰會由密碼金鑰供應商儲存,公開金鑰則會傳回給信賴方 (RP) 的伺服器儲存。伺服器可以使用配對的公開金鑰,驗證以相同密碼金鑰簽署的簽章,藉此驗證使用者身分。公開金鑰憑證上的「使用者在場」(UP) 旗標可證明有人在驗證期間與裝置互動。

使用者驗證是選用的安全層級,可確保驗證期間在場的是正確的使用者,而不只是某個人 (使用者在場驗證可確保這一點)。在智慧型手機上,通常是透過螢幕鎖定機制完成,無論是生物特徵辨識,還是 PIN 碼或密碼。系統會在密碼金鑰註冊和驗證期間,透過驗證器資料傳回的「UV」旗標,回報是否已執行使用者驗證

螢幕截圖:macOS 上的 iCloud 鑰匙圈使用者驗證對話方塊。對話方塊會提示使用者透過 Touch ID 登入,並顯示要求驗證的來源和使用者名稱。對話方塊右上角有一個標示為「取消」的按鈕。
macOS 上的 iCloud 鑰匙圈使用者驗證對話方塊。
螢幕截圖:Android 版 Chrome 的使用者驗證對話方塊。對話方塊會提示使用者透過臉部辨識或指紋偵測驗證身分,並顯示要求驗證的來源。左下方會顯示使用 PIN 碼驗證的選項。
Android 版 Chrome 的使用者驗證對話方塊。

伺服器如何驗證 UP 和 UV

使用者在場 (UP) 和使用者已驗證 (UV) 布林值旗標會透過驗證器資料欄位傳送至伺服器。驗證期間,您可以使用儲存的公開金鑰驗證簽名,藉此驗證驗證器資料欄位的內容。只要簽章有效,伺服器就會將標記視為真實。

驗證資料結構的圖示。從左到右,資料結構的每個部分分別是「RP ID HASH」(32 個位元組)、「FLAGS」(1 個位元組)、「COUNTER」(4 個位元組,大端 uint32)、「ATTESTE CRED. 「DATA」(如有,長度可變) 和「EXTENSIONS」(如有,長度可變 (CBOR))。「FLAGS」部分已展開,顯示潛在標記清單,從左到右依序標示為「ED」、「AT」、「0」、「BS」、「BE」、「UV」、「0」和「UP」。
公開金鑰憑證中的驗證器資料欄位。

在密碼金鑰註冊和驗證程序中,伺服器應根據需求檢查 UP 旗標是否為 truefalse,以及 UV 旗標是否為 truefalse

指定 userVerification 參數

根據 WebAuthn 規格,RP 可以在憑證建立和判斷時,透過 userVerification 參數要求使用者驗證。可接受 'preferred''required''discouraged',分別代表:

  • 'preferred' (預設):偏好在裝置上使用使用者驗證方法,但如果無法使用,可以略過。如果已執行使用者驗證,回應憑證會包含 true 的 UV 旗標值;如果未執行 UV,則會包含 false
  • 'required':必須叫用裝置上可用的使用者驗證方法。如果沒有,要求就會在本機失敗。也就是說,回應憑證一律會傳回 UV 旗標設為 true 的值。
  • 'discouraged':不建議使用使用者驗證方法。不過,視裝置而定,系統仍可能執行使用者驗證,且 UV 旗標可能包含 truefalse

密碼金鑰建立作業的程式碼範例:

const publicKeyCredentialCreationOptions = {
  // ...
  authenticatorSelection: {
    authenticatorAttachment: 'platform',
    residentKey: 'required',
    requireResidentKey: true,
    userVerification: 'preferred'
  }
};

const credential = await navigator.credentials.create({
  publicKey: publicKeyCredentialCreationOptions
});

密碼金鑰驗證的範例程式碼:

const publicKeyCredentialRequestOptions = {
  challenge: /* Omitted challenge data... */,
  rpId: 'example.com',
  userVerification: 'preferred'
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions
});

您應該選擇哪種「userVerification」?

應使用的 userVerification 值取決於應用程式需求和使用者體驗需求。

使用時機 userVerification='preferred'

如果使用者體驗比保護措施重要,請使用 userVerification='preferred'

在某些環境中,使用者驗證帶來的困擾大於保護作用。舉例來說,如果 macOS 裝置不支援 Touch ID (因為裝置不支援、已停用,或裝置處於闔蓋模式),系統會要求使用者改為輸入系統密碼。這會造成阻礙,使用者可能完全放棄驗證。如果減少摩擦力對您而言更重要,請使用 userVerification='preferred'

螢幕截圖:macOS 上的密碼金鑰對話方塊,會在 Touch ID 無法使用時顯示。對話方塊會顯示要求驗證的來源和使用者名稱等資訊。對話方塊右上角有一個標示為「取消」的按鈕。
如果無法使用 Touch ID,macOS 會顯示密碼金鑰對話方塊。

使用 userVerification='preferred' 時,如果使用者驗證成功,UV 旗標會是 true;如果略過使用者驗證,則為 false。舉例來說,在沒有 Touch ID 的 macOS 上,系統會要求使用者點選按鈕略過使用者驗證,而公開金鑰憑證會包含 false UV 旗標。

UV 標記隨後可做為風險分析的信號。如果登入嘗試因其他因素而顯得有風險,您可能需要向未經驗證的使用者提出額外的登入驗證問題。

使用時機 userVerification='required'

如果您認為 UP 和 UV 都是絕對必要的,請使用 userVerification='required'

這個選項的缺點是使用者登入時可能會遇到更多阻礙。舉例來說,在沒有 Touch ID 的 macOS 上,系統會要求使用者輸入系統密碼。

使用 userVerification='required',確保使用者驗證是在裝置上執行。確認伺服器會驗證 UV 旗標是否為 true

結論

依賴方可運用使用者驗證功能,評估裝置擁有者登入的可能性。是否要強制驗證使用者,或視備援登入機制對使用者流程的影響程度而定,由開發人員自行決定。請確認伺服器會檢查密碼金鑰使用者驗證的 UP 標記和 UV 標記。