透過表單自動填入功能使用密碼金鑰登入

建立使用密碼金鑰的登入體驗,同時仍配合現有密碼使用者。

密碼金鑰會取代密碼,讓網路上的使用者帳戶更安全、更簡單,且更容易使用。不過,從密碼型驗證轉換為密碼金鑰驗證可能會使使用者體驗變得複雜。使用表單自動填入功能建議密碼金鑰,有助於創造整合式體驗。

為什麼要使用表單自動填入功能,透過密碼金鑰登入?

使用者只要設定密碼金鑰,就能使用指紋、臉孔或裝置 PIN 碼登入網站。

在理想情況下,沒有密碼使用者,而且驗證流程可以只像單一登入按鈕一樣簡單。使用者輕觸按鈕後,畫面上會彈出帳戶選取器對話方塊,方便使用者挑選帳戶,並解鎖螢幕進行驗證並登入。

不過,從密碼改用密碼金鑰驗證可能並不容易。隨著使用者改用密碼金鑰,使用密碼和網站的使用者仍需要同時因應這兩種使用者的需求。使用者不應記得自己切換到密碼金鑰的網站,因此若要求使用者選擇要使用的方法,將會造成使用者體驗不佳。

密碼金鑰也是一項新技術。如果網站說明這些原則,並確保使用者能夠安心使用,可能會是一大挑戰。我們可以透過熟悉的使用者體驗自動填入密碼來解決這兩個問題。

條件式 UI

如要為密碼金鑰和密碼使用者打造有效的使用者體驗,您可以在自動填入建議中加入密碼金鑰。這稱為條件式 UI,屬於 WebAuthn 標準的一部分。

使用者輕觸使用者名稱輸入欄位後,自動填入建議對話方塊會醒目顯示已儲存的密碼金鑰,以及密碼自動填入建議。使用者接著可以選擇帳戶,並使用裝置螢幕鎖定功能登入。

如此一來,使用者就能以現有表單登入網站,就像沒有任何變更一樣,但在沒有密碼金鑰的情況下,可享有密碼金鑰的額外安全優勢

運作方式

如要以密碼金鑰進行驗證,請使用 WebAuthn API

密碼金鑰驗證流程中的四個元件為:使用者:

  • 後端:您的後端伺服器,用於保存儲存公開金鑰的帳戶資料庫,以及密碼金鑰的其他中繼資料。
  • 前端:與瀏覽器通訊並將擷取要求傳送至後端的前端。
  • 瀏覽器:執行 JavaScript 的使用者瀏覽器。
  • Authenticator:建立並儲存密碼金鑰的使用者驗證器。此裝置可能與瀏覽器相同 (例如使用 Windows Hello 時),也可能是在其他裝置 (例如手機) 上。
密碼金鑰驗證圖表
  1. 使用者到達前端後,就會要求後端進行驗證,以使用密碼金鑰進行驗證,並呼叫 navigator.credentials.get() 以使用密碼金鑰進行驗證。這會傳回 Promise
  2. 當使用者在登入欄位放置遊標時,瀏覽器會顯示密碼自動填入對話方塊,包括密碼金鑰。如果使用者選取密碼金鑰,畫面上會顯示驗證對話方塊。
  3. 使用者透過裝置的螢幕鎖定功能驗證身分後,就會解決承諾,並將公開金鑰憑證傳回至前端。
  4. 前端將公開金鑰憑證傳送至後端。後端會根據資料庫中相符帳戶的公開金鑰驗證簽章。如果成功,使用者就會登入。

必備條件

iOS 16、iPadOS 16 和 macOS Ventura 的 Safari 公開支援條件式 WebAuthn UI。這項設定也適用於 Android、macOS 和 Windows 11 22H2 的 Chrome。

透過表單自動填入功能使用密碼金鑰進行驗證

使用者想要登入時,您可以進行條件式 WebAuthn get 呼叫,指出密碼金鑰可能包含自動填入建議。對 WebAuthnnavigator.credentials.get() API 的條件式呼叫不會顯示使用者介面,且會一直處於待處理狀態,直到使用者選擇要透過自動填入建議登入的帳戶為止。使用者選取密碼金鑰後,瀏覽器就會使用憑證來解決承諾,而不是填寫登入表單。接著,網頁就能負責讓使用者登入

註解表單輸入欄位

視需要在使用者名稱 input 欄位中加入 autocomplete 屬性。 附加 usernamewebauthn 做為權杖,讓它建議密碼金鑰。

<input type="text" name="username" autocomplete="username webauthn" ...>

功能偵測

叫用條件式 WebAuthn API 呼叫前,請先檢查下列事項:

  • 瀏覽器支援 WebAuthn。
  • 瀏覽器支援 WebAuthn 條件式 UI。
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.​​isConditionalMediationAvailable) {  
  // Check if conditional mediation is available.  
  const isCMA = await PublicKeyCredential.​​isConditionalMediationAvailable();  
  if (isCMA) {  
    // Call WebAuthn authentication  
  }  
}  

從 RP 伺服器擷取驗證問題

從 RP 伺服器擷取呼叫 navigator.credentials.get() 所需的驗證:

  • challenge:在 ArrayBuffer 中由伺服器產生的驗證問題。這是為了避免重送攻擊。請務必在每次嘗試登入時產生新的驗證問題,並在經過一段時間或登入失敗後忽略此驗證。將其視為 CSRF 權杖。
  • allowCredentials:此驗證可接受的憑證陣列。傳遞空白陣列,讓使用者從瀏覽器顯示的清單中選取可用密碼金鑰。
  • userVerification:指出使用裝置螢幕鎖定功能的使用者驗證方式為 "required""preferred""discouraged"。預設值為 "preferred",表示驗證器可能會略過使用者驗證程序。請將這個屬性設為 "preferred" 或省略此屬性。

使用 conditional 旗標呼叫 WebAuthn API,驗證使用者

呼叫 navigator.credentials.get() 即可開始等待使用者驗證。

// To abort a WebAuthn call, instantiate an `AbortController`.
const abortController = new AbortController();

const publicKeyCredentialRequestOptions = {
  // Server generated challenge
  challenge: ****,
  // The same RP ID as used during registration
  rpId: 'example.com',
};

const credential = await navigator.credentials.get({
  publicKey: publicKeyCredentialRequestOptions,
  signal: abortController.signal,
  // Specify 'conditional' to activate conditional UI
  mediation: 'conditional'
});
  • rpId:RP ID 是網域,網站可以指定網域或可註冊的後置字串。這個值必須與建立密碼金鑰時使用的 rp.id 相符。

請記得指定 mediation: 'conditional',讓要求有條件地提出要求。

將傳回的公開金鑰憑證傳送至 RP 伺服器

使用者選取帳戶並使用裝置的螢幕鎖定功能同意之後,承諾會將 PublicKeyCredential 物件傳回 RP 前端。

承諾會因為各種原因而遭到拒絕。您需要根據 Error 物件的 name 屬性,視情況處理錯誤:

  • NotAllowedError:使用者已取消作業。
  • 其他例外狀況:發生未預期的問題。瀏覽器會向使用者顯示錯誤對話方塊。

公開金鑰憑證物件包含下列屬性:

  • id:已驗證密碼金鑰憑證的 Base64url 編碼 ID。
  • rawId:憑證 ID 的 ArrayBuffer 版本。
  • response.clientDataJSON:用戶端資料的 ArrayBuffer。此欄位包含驗證問題等資訊,以及 RP 伺服器需要驗證的來源。
  • response.authenticatorData:驗證器資料的 ArrayBuffer。這個欄位包含 RP ID 等資訊。
  • response.signature:簽名的 ArrayBuffer。這個值是憑證的核心,且需要在伺服器上驗證。
  • response.userHandle:包含建立時設定的使用者 ID 的 ArrayBuffer。如果伺服器需要挑選其使用的 ID 值,或是後端希望避免建立憑證 ID 索引,可以使用這個值,而非憑證 ID。
  • authenticatorAttachment:如果這個憑證來自本機裝置,系統會傳回 platform。否則 cross-platform,特別是使用者使用手機登入時。如果使用者需要使用手機登入帳戶,建議您提示他們在本機裝置上建立密碼金鑰
  • type:這個欄位一律設為 "public-key"

如果您使用程式庫在 RP 伺服器上處理公開金鑰憑證物件,建議您在使用 base64url 進行部分編碼後,將整個物件傳送至伺服器。

驗證簽名

在伺服器上收到公開金鑰憑證時,請將該憑證傳遞至 FIDO 程式庫以處理物件。

使用 id 屬性查詢相符的憑證 ID (如需判斷使用者帳戶,請使用 userHandle 屬性,也就是您在建立憑證時指定的 user.id)。請查看憑證的 signature 能否使用儲存的公開金鑰進行驗證。為此,建議您使用伺服器端程式庫或解決方案,不要自行編寫程式碼。您可以在 awesome-webauth GitHub 存放區中找到開放原始碼程式庫

使用相符的公開金鑰驗證憑證後,請讓使用者登入。

資源