密碼金鑰可讓使用者提升使用者帳戶的安全性、操作便利性和便利性。
使用密碼金鑰而非密碼是網站的絕佳方式,能為網站提供更安全、更簡單、更易於使用及無密碼的使用者帳戶。有了密碼金鑰,使用者就能透過指紋、臉孔或裝置 PIN 碼登入網站或應用程式。
您必須先建立密碼金鑰、與使用者帳戶建立關聯,並將密碼金鑰儲存在伺服器上,使用者才能使用密碼金鑰登入。
運作方式
在下列情況下,系統可能會要求使用者建立密碼金鑰:
- 使用者使用密碼登入時。
- 當使用者透過其他裝置的密碼金鑰登入 (即
authenticatorAttachment
為cross-platform
) 時。 - 使用者可以透過專屬頁面管理密碼金鑰。
如要建立密碼金鑰,請使用 WebAuthn API。
密碼金鑰註冊流程的四個元件如下:
- 後端:您的後端伺服器,保留帳戶資料庫儲存公開金鑰和其他中繼資料。
- 前端:與瀏覽器通訊,並將擷取要求傳送至後端的前端。
- 瀏覽器:執行 JavaScript 的使用者瀏覽器。
- Authenticator:用來建立及儲存密碼金鑰的使用者驗證器。這可能包括在瀏覽器所用裝置 (例如使用 Windows Hello) 或其他裝置 (例如手機) 上的密碼管理工具。
![密碼金鑰註冊圖表](https://web.dev/static/articles/passkey-registration/image/passkey-registration-diagram.png?authuser=7&hl=zh-tw)
將密碼金鑰新增至現有使用者帳戶的流程如下:
- 使用者登入網站。
- 使用者登入後,會要求在前端建立密碼金鑰,例如按下「建立密碼金鑰」按鈕。
- 前端會從後端要求資訊以建立密碼金鑰,例如使用者資訊、驗證問題和要排除的憑證 ID。
- 前端呼叫
navigator.credentials.create()
以建立密碼金鑰。這個呼叫會傳回承諾值。 - 當使用者使用裝置的螢幕鎖定功能表示同意後,系統就會建立密碼金鑰。系統已解析承諾,並將公開金鑰憑證傳回前端。
- 前端將公開金鑰憑證傳送至後端,並儲存憑證 ID 和與使用者帳戶相關聯的公開金鑰,供日後的驗證使用。
相容性
大部分瀏覽器都支援 WebAuthn,但有些微差異。請參閱「裝置支援 - passwordss.dev」,瞭解哪些類型的瀏覽器和作業系統支援建立密碼金鑰。
建立新的密碼金鑰
以下說明如何在要求建立新密碼金鑰時,前端運作。
特徵偵測
顯示「建立新的密碼金鑰」按鈕前,請先確認下列事項:
- 瀏覽器透過
PublicKeyCredential
支援 WebAuthn。
- 裝置使用
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()
支援平台驗證器 (可以建立密碼金鑰並使用密碼金鑰進行驗證)。
- 瀏覽器透過
PublicKeyCredenital.isConditionalMediationAvailable()
支援 WebAuthn 條件式 UI。
// Availability of `window.PublicKeyCredential` means WebAuthn is usable.
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.
// `isConditionalMediationAvailable` means the feature detection is usable.
if (window.PublicKeyCredential &&
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&
PublicKeyCredential.isConditionalMediationAvailable) {
// Check if user verifying platform authenticator is available.
Promise.all([
PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),
PublicKeyCredential.isConditionalMediationAvailable(),
]).then(results => {
if (results.every(r => r === true)) {
// Display "Create a new passkey" button
}
});
}
在符合所有條件前,這個瀏覽器將不支援密碼金鑰。在這之前,系統才會顯示「建立新的密碼金鑰」按鈕。
從後端擷取重要資訊
在使用者點選按鈕時,擷取重要資訊,從後端呼叫 navigator.credentials.create()
:
challenge
:在 ArrayBuffer 中針對這項註冊作業產生的伺服器產生的驗證問題。這是必要項目,但除非進行認證,否則未在註冊期間使用。請注意,本文未提及的進階主題。user.id
:使用者的專屬 ID。這個值必須為 ArrayBuffer,其中不包含個人識別資訊,例如電子郵件地址或使用者名稱。每個帳戶產生的 16 位元組隨機值通常很好。user.name
:這個欄位應保留使用者可識別的帳戶專屬 ID,例如電子郵件地址或使用者名稱。這會顯示在帳戶選取器中。(如果使用使用者名稱,請使用與密碼驗證相同的值)。user.displayName
:這個欄位為必填欄位,可讓使用者更容易理解。這個名稱可以重複,可以是使用者選擇的名稱。如果您的網站沒有可加入的合適值,請傳送空字串。視瀏覽器而定,帳戶選取器可能會顯示這項資訊。excludeCredentials
:提供已註冊的憑證 ID 清單,防止註冊同一部裝置。transports
成員 (如有提供) 應包含在每個憑證註冊期間呼叫getTransports()
的結果。
呼叫 WebAuthn API 以建立密碼金鑰
請呼叫 navigator.credentials.create()
以建立新的密碼金鑰。API 會傳回承諾,等待使用者與顯示強制回應對話方塊的互動。
const publicKeyCredentialCreationOptions = {
challenge: *****,
rp: {
name: "Example",
id: "example.com",
},
user: {
id: *****,
name: "john78",
displayName: "John",
},
pubKeyCredParams: [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}],
excludeCredentials: [{
id: *****,
type: 'public-key',
transports: ['internal'],
}],
authenticatorSelection: {
authenticatorAttachment: "platform",
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// Encode and send the credential to the server for verification.
上述未說明的參數如下:
rp.id
:RP ID 是網域,網站可以指定網域或可註冊的後置字串。舉例來說,如果 RP 來源為https://login.example.com:1337
,則 RP ID 可以是login.example.com
或example.com
。如果將 RP ID 指定為example.com
,使用者即可在login.example.com
或example.com
的任何子網域上進行驗證。rp.name
:RP 的名稱。pubKeyCredParams
:這個欄位會指定 RP 支援的公開金鑰演算法。建議您將其設為[{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}]
。這會指定對使用 P-256 和 RSA PKCS#1 的 ECDSA 提供支援,並支援這些 ECDSA。authenticatorSelection.authenticatorAttachment
:如果這個密碼金鑰的建立程序是密碼升級 (例如登入後的促銷活動),請將其設為"platform"
。"platform"
表示 RP 需要的平台驗證器 (內嵌於平台裝置的驗證器),因此不會提示插入 USB 安全金鑰等。使用者可以選擇較簡單的建立密碼金鑰。authenticatorSelection.requireResidentKey
:將其設為布林值「true」。可搜尋的憑證 (常駐金鑰) 會將使用者資訊儲存至密碼金鑰,讓使用者在驗證時選取帳戶。如要進一步瞭解可搜尋的憑證,請參閱「可搜尋的憑證深入說明」一文authenticatorSelection.userVerification
:指出使用裝置螢幕鎖定功能進行使用者的驗證是"required"
、"preferred"
或"discouraged"
。預設值為"preferred"
,表示驗證器可能會略過使用者驗證。請將這個屬性設為"preferred"
或省略屬性。
將傳回的公開金鑰憑證傳送至後端
使用者透過裝置的螢幕鎖定功能表示同意後,系統就會建立密碼金鑰,並將 PublicKeyCredential 物件傳回至前端。
承諾產品可能會基於各種原因遭拒。您可以檢查 Error
物件的 name
屬性來處理這些錯誤:
InvalidStateError
:裝置上已有密碼金鑰。系統不會向使用者顯示錯誤對話方塊,且網站不應將此視為錯誤,也就是使用者希望註冊本機裝置且發生了這個錯誤。NotAllowedError
:使用者已取消作業。- 其他例外狀況:發生非預期的狀況。瀏覽器會向使用者顯示錯誤對話方塊。
公開金鑰憑證物件包含下列屬性:
id
:已建立密碼金鑰的 Base64URL 編碼 ID。這個 ID 可協助瀏覽器判斷進行驗證後,裝置中是否有相符的密碼金鑰。這個值需要儲存在後端的資料庫中。rawId
:憑證 ID 的 ArrayBuffer 版本。response.clientDataJSON
:ArrayBuffer 編碼的客戶資料。response.attestationObject
:ArrayBuffer 編碼的認證物件。其中包含 RP ID、旗標和公開金鑰等重要資訊。authenticatorAttachment
:在支援密碼金鑰的裝置上建立這個憑證時,傳回"platform"
。type
:這個欄位一律設為"public-key"
。
若您使用程式庫在後端處理公開金鑰憑證物件,建議您先使用 base64url 進行部分編碼,再將整個物件傳送至後端。
儲存憑證
在後端收到公開金鑰憑證後,將憑證傳送給 FIDO 程式庫來處理物件。
接著,您可以將從憑證擷取的資訊儲存到資料庫,以供日後使用。下列清單包含一些可以儲存的一般屬性:
- 憑證 ID (主金鑰)
- 使用者 ID
- 公開金鑰
公開金鑰憑證也包括了您可能會想在資料庫中儲存的下列資訊:
- 備份資格標記:
true
(如果裝置符合密碼金鑰同步處理的資格)。 - 備份狀態標記:如果已建立的密碼金鑰實際上設為同步處理,則為
true
。 - 傳輸:裝置支援的傳輸清單:
"internal"
表示裝置支援密碼金鑰,"hybrid"
表示裝置也支援另一部裝置上的驗證作業。
如需詳細操作說明,請參閱「伺服器端密碼金鑰註冊」一文
如要驗證使用者,請參閱「透過表單自動填入功能使用密碼金鑰登入」。