使用者驗證深入解析

本文將說明 WebAuthn 中的 userVerification 為何,以及在建立密碼金鑰或驗證時指定 userVerification 後,瀏覽器會產生哪些行為。

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

密碼金鑰是根據公開金鑰密碼編譯技術建構而成。建立密碼金鑰後,系統會產生公開/私密金鑰組,密碼金鑰供應商會儲存私密金鑰,然後將公開金鑰傳回依賴方 (RP) 伺服器加以儲存。伺服器可以使用配對的公開金鑰,驗證由同一個密碼金鑰簽署的簽章,藉此驗證使用者。公用金鑰憑證上的「使用者在場」(UP) 旗標,可證明在驗證期間有人與裝置互動。

使用者驗證是一項選用的安全層,可在驗證期間確認使用者身分,而非僅確認使用者是否在場。在智慧型手機上,螢幕鎖定機制通常是透過生物特徵辨識技術、PIN 碼或密碼來完成。在密碼金鑰註冊和驗證期間,系統會在 authenticator 資料中傳回「UV」標記,用於回報是否已執行使用者驗證

macOS 版 iCloud 鑰匙圈的使用者驗證對話方塊螢幕截圖。對話方塊會提示使用者使用 Touch ID 登入,並顯示要求驗證的來源和使用者名稱。對話方塊的右上方有一個標示為「取消」的按鈕。
macOS 版 iCloud 鑰匙圈的使用者驗證對話方塊。
Chrome 適用於 Android 的使用者驗證對話方塊螢幕截圖。對話方塊會提示使用者使用臉部辨識或指紋偵測功能來驗證身分,並顯示要求驗證的來源。你可以在左下方使用 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」。
公開金鑰憑證中的 Authenticator 資料欄位。

在密碼金鑰註冊和驗證作業中,伺服器應檢查 UP 旗標是否為 true,以及 UV 旗標是否為 truefalse,具體取決於需求。

指定 userVerification 參數

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

  • 'preferred' (預設):建議在裝置上採用使用者驗證方法,如果無法使用,可以略過這個步驟。如果已執行使用者驗證,回應憑證會包含 UV 標記值 true,如果未執行 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 功能時,裝置不支援這項功能 (例如裝置不支援、已停用,或是處於 clamshell 模式),系統就會要求使用者輸入系統密碼。這會造成問題,使用者也可能完全放棄驗證。如果您更重視消除摩擦,請使用 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 標記。