Passkey、WebAuthn 與 FIDO2
Passkey 是近年身份驗證裡最重要的變化之一。
它想解決的不是:
把密碼變得更複雜。而是:
讓使用者不再需要輸入可被釣魚、重用、外洩的密碼。很多人第一次看到 Passkey 會以為:
這就是用指紋或 Face ID 登入。這個說法只對了一半。
比較準確地說:
Passkey 是一組和網站綁定的公私鑰憑證。
指紋、Face ID、PIN 通常只是用來解鎖本機私鑰。
真正向網站證明身份的是私鑰簽章。這也是它比 SMS OTP、Email OTP、TOTP 更抗釣魚的關鍵。
一、 一句話回答
如果面試官問:
Passkey、WebAuthn、FIDO2 是什麼?為什麼比較安全?
可以先回答:
Passkey 是基於 WebAuthn / FIDO2 的公私鑰登入憑證。註冊時,瀏覽器或平台驗證器會為特定網站的 RP ID 產生一組 credential,私鑰保存在使用者裝置或同步憑證管理系統中,伺服器只保存 public key、credential id、sign counter 等資料。登入時伺服器產生 challenge,瀏覽器要求 authenticator 用私鑰簽署 challenge,伺服器用 public key 驗證簽章,同時檢查 challenge、origin、RP ID、user presence、user verification 等資訊。因為私鑰不會送到伺服器,而且 credential 與網站 origin / RP ID 綁定,釣魚網站即使長得一樣,也無法讓使用者的 passkey 對真正網站簽章,所以 Passkey / WebAuthn 具備比 OTP 更好的釣魚抗性。
短一點可以說:
Passkey 不是把密碼存在裝置裡,
而是用網站專屬的私鑰簽署 challenge。二、 名詞先拆開
| 名稱 | 意義 |
|---|---|
| Passkey | 使用者可感知的無密碼登入憑證,通常可同步 |
| WebAuthn | W3C 定義的瀏覽器 API 與資料結構 |
| FIDO2 | FIDO Alliance 的標準集合,通常包含 WebAuthn + CTAP |
| CTAP | Client to Authenticator Protocol,瀏覽器和 authenticator 溝通 |
| Authenticator | 產生與保存私鑰的裝置或元件 |
| Relying Party | 依賴 WebAuthn 驗證使用者的網站或服務 |
| Credential | 某個 RP 下的一組公私鑰登入憑證 |
可以這樣理解:
WebAuthn:瀏覽器給網站用的 API。
CTAP:瀏覽器和安全金鑰 / 手機等 authenticator 溝通的協議。
FIDO2:WebAuthn + CTAP 這套公私鑰登入標準。
Passkey:建立在這些標準上的使用者體驗與憑證形式。三、 Passkey 為什麼抗釣魚
傳統密碼和 OTP 的問題是:
使用者可以把它輸入到假網站。例如:
真網站:example.com
假網站:examp1e.com使用者看錯網址,把密碼和 TOTP 輸入假網站,攻擊者就能即時轉送到真網站。
Passkey 的關鍵差異是:
credential 和 RP ID / origin 綁定。使用者在 example.com 註冊的 passkey,不能被 examp1e.com 使用。
登入時瀏覽器會把真實 origin 放進 client data,authenticator 也會針對 RP ID 做簽章。伺服器驗證時會檢查:
- challenge 是否正確。
- origin 是否是預期網站。
- RP ID hash 是否符合。
- 簽章是否由該 credential 的私鑰產生。
所以釣魚網站就算長得一模一樣,也無法取得能登入真網站的簽章。
這就是 phishing-resistant 的核心。
四、公私鑰模型
Passkey 註冊時會產生一組 key pair:
private key:留在使用者 authenticator 裡
public key:交給伺服器保存伺服器永遠不需要知道 private key。
登入時:
伺服器發 challenge
authenticator 用 private key 簽章
伺服器用 public key 驗簽概念:
這和密碼最大的差別:
| 比較 | 密碼 | Passkey |
|---|---|---|
| 使用者輸入秘密 | 會 | 不會 |
| 伺服器保存 | password hash | public key |
| 可被釣魚轉送 | 容易 | 因 origin/RP ID 綁定而困難 |
| 可重用 | 常見 | 每個 RP 不同 credential |
| 外洩影響 | hash 可能被破解 | public key 外洩不能登入 |
五、 Authenticator 類型
Authenticator 是保存私鑰並執行簽章的東西。
常見分兩類。
Platform Authenticator
平台驗證器內建在裝置裡。
例如:
- iPhone / iPad 的 iCloud Keychain passkey。
- Android 裝置的 Google Password Manager passkey。
- macOS Touch ID。
- Windows Hello。
優點:
- 使用者體驗好。
- 可以用指紋、臉部、裝置 PIN 解鎖。
- 常支援跨裝置同步。
Roaming Authenticator
漫遊驗證器是外接或可攜帶的 authenticator。
例如:
- YubiKey。
- Titan Security Key。
- 其他 FIDO2 security key。
優點:
- 高安全性。
- 適合企業管理員、高風險帳號。
- 有些硬體金鑰的私鑰不可匯出。
缺點:
- 成本較高。
- 使用者要保管實體 key。
- 遺失時要有備援。
六、 User Presence 與 User Verification
WebAuthn 有兩個很重要的概念。
User Presence
User Presence,簡稱 UP,代表使用者有做某個動作。
例如:
- 觸碰安全金鑰。
- 按下裝置確認。
它證明:
不是背景程式偷偷簽章,使用者有參與。User Verification
User Verification,簡稱 UV,代表 authenticator 驗證了使用者本人。
例如:
- 指紋。
- Face ID。
- 裝置 PIN。
- Windows Hello。
它證明:
不只是有人按了裝置,而是通過本機解鎖驗證。設定上常見:
userVerification: 'preferred' | 'required' | 'discouraged'高風險登入或無密碼登入通常會要求:
userVerification = required因為如果只要求 presence,撿到安全金鑰的人可能只要按一下就能登入。
七、 註冊流程
註冊 Passkey 不是把密碼存起來。
它是讓 authenticator 為你的網站產生新 credential。
流程:
後端回給前端的是:
type PublicKeyCredentialCreationOptions = {
challenge: ArrayBuffer
rp: {
id: string
name: string
}
user: {
id: ArrayBuffer
name: string
displayName: string
}
pubKeyCredParams: Array<{
type: 'public-key'
alg: number
}>
authenticatorSelection?: {
residentKey?: 'required' | 'preferred' | 'discouraged'
userVerification?: 'required' | 'preferred' | 'discouraged'
}
timeout?: number
attestation?: 'none' | 'direct' | 'enterprise'
}註冊時後端要保存 challenge,驗證回來時確認它沒有被換掉。
八、 登入流程
登入時不傳密碼,而是驗簽。
流程:
重點:
伺服器不是驗證使用者輸入的秘密,
而是驗證 authenticator 對 challenge 的簽章。九、 後端驗證重點
WebAuthn 驗證不能只看:
有回 credential id 就成功。註冊時要驗:
- challenge。
- origin。
- RP ID hash。
- type 是否是
webauthn.create。 - user presence。
- user verification,若要求。
- attestation,若產品需要。
- public key 格式。
- credential id 是否已存在。
登入時要驗:
- challenge。
- origin。
- RP ID hash。
- type 是否是
webauthn.get。 - credential id 是否屬於該 user 或可被 discover。
- signature 是否正確。
- user presence。
- user verification,若要求。
- sign counter,若適用。
實務上應使用成熟 library,例如 SimpleWebAuthn、webauthn-rs、duo-labs/webauthn 等生態工具,不建議手寫 CBOR / COSE / attestation parsing。
十、 RP ID 與 Origin
這是 WebAuthn 安全性的核心之一。
Origin
origin 包含:
scheme + host + port例如:
https://app.example.comRP ID
RP ID 通常是 domain:
example.com或:
app.example.comcredential 會和 RP ID 綁定。
常見設計:
rp.id = example.com這樣可允許:
app.example.com
admin.example.com在同一 RP ID 下使用 credential,前提是 origin 驗證也正確。
但不能跨到:
evil-example.com設定 RP ID 時要小心:
- 本機開發環境。
- 多子網域。
- 多租戶 custom domain。
- staging / production 分離。
- mobile app deep link 或 native app。
不要為了方便把驗證放寬。
十一、 Discoverable Credential 與使用者名稱
Passkey 常支援「不用先輸入帳號」的登入體驗。
這依賴 discoverable credential,也常被稱為 resident key。
流程是:
使用者點 Passkey 登入
瀏覽器 / authenticator 顯示可用帳號
使用者選擇帳號
authenticator 回傳 credential
伺服器根據 credential id 找 user如果不是 discoverable credential,使用者可能要先輸入 email,伺服器再給 allowCredentials。
兩種都可以:
| 類型 | 體驗 | 特點 |
|---|---|---|
| Discoverable credential | 可無帳號輸入 | 更像完整 passkey 體驗 |
| Non-discoverable credential | 先輸入帳號 | 較傳統,server 指定 credential |
現代 Passkey 體驗通常會偏向 discoverable credential。
十二、 資料表設計
可以設計一張 webauthn_credentials:
create table webauthn_credentials (
id uuid primary key,
user_id uuid not null references users(id),
credential_id text not null unique,
public_key text not null,
rp_id text not null,
sign_count bigint,
transports text[],
backup_eligible boolean,
backup_state boolean,
user_verified_required boolean not null default true,
name text,
created_at timestamp not null,
last_used_at timestamp
);常見欄位:
| 欄位 | 說明 |
|---|---|
| credential_id | authenticator 建立的 credential 識別 |
| public_key | 伺服器用來驗簽 |
| sign_count | 簽章計數,用於偵測 clone,視 authenticator 支援 |
| transports | usb、nfc、ble、internal 等 |
| backup_eligible | 是否可備份 / 同步 |
| backup_state | 目前是否被備份 |
| name | 使用者自訂名稱,例如 MacBook Touch ID |
| last_used_at | 最近使用時間 |
也要有 challenge store:
webauthn_challenges保存:
- user id 或 anonymous flow。
- challenge。
- purpose。
- expires_at。
- used_at。
- rp_id。
- expected_origin。
challenge 必須短效且一次性。
十三、 Passkey 是 MFA 還是 Passwordless?
答案要看它的使用方式與 authenticator。
Passkey 可以用在:
密碼 + Passkey這時它是第二因素。
也可以用在:
Passkey only這時它是無密碼登入。
如果 authenticator 要求 user verification,例如生物特徵或裝置 PIN,則一次登入中包含:
- 持有因素:使用者控制私鑰裝置。
- 知識或生物因素:PIN / biometric 解鎖本機私鑰。
所以平台 passkey 常被視為強身份驗證方式。
但實務上仍要看:
- userVerification 是否 required。
- authenticator 是否同步。
- 是否允許多裝置。
- 帳號恢復流程。
- 企業政策。
- 風險場景。
十四、 Syncable Passkeys
現代 Passkey 很多是可同步的。
例如:
- iCloud Keychain 在 Apple 裝置間同步。
- Google Password Manager 在 Android / Chrome 生態同步。
- 密碼管理器同步 passkeys。
這大幅改善使用體驗:
換手機也不一定遺失 passkey。但安全模型也和硬體安全金鑰不同。
硬體安全金鑰通常強調:
private key 不可匯出。同步 passkey 則允許 key 在受保護的同步系統中跨裝置可用。
這不是壞事,但系統要理解差異:
| 類型 | 優點 | 風險/考量 |
|---|---|---|
| Syncable passkey | 體驗好、不易因換裝置遺失 | 信任平台同步安全 |
| Hardware security key | 私鑰不可匯出、高安全 | 成本、遺失、備援 |
NIST SP 800-63B 已納入 syncable authenticators 的相關要求與風險考量。產品設計時不要把所有 passkey 都當成同一種保證等級,尤其在企業或高風險場景。
十五、 Passkey 與 TOTP 比較
| 比較 | TOTP | Passkey / WebAuthn |
|---|---|---|
| 核心 | shared secret + time | public/private key + challenge |
| 伺服器保存 | encrypted secret | public key |
| 使用者輸入 code | 需要 | 不需要 |
| 是否可被即時釣魚轉送 | 可以 | 因 origin/RP ID 綁定而困難 |
| 裝置遺失 | 需要 backup / recovery | 同步 passkey 較好恢復,硬體 key 需備援 |
| 適合 | 一般 MFA | 高安全、無密碼、釣魚抗性 |
TOTP 的問題是:
使用者可以把 code 輸入假網站。Passkey 的優勢是:
簽章只對正確 RP / origin 有效。這就是為什麼 Passkey 是下一代身份驗證的重要方向。
十六、 帳號恢復與備援
Passkey 很安全,但仍要處理:
裝置不見了怎麼辦?備援方式:
- 第二個 passkey。
- 硬體安全金鑰。
- Backup codes。
- TOTP。
- 已登入可信裝置。
- 企業管理員恢復。
- 高風險身份驗證。
不要只有一個 passkey。
好的設計會鼓勵:
至少新增兩個登入方式。例如:
- 手機 passkey。
- 筆電 passkey。
- backup code。
高風險帳號可要求:
- 至少兩個 security keys。
- 或 passkey + hardware key。
十七、 常見錯誤
1. 以為 Passkey 是存密碼
錯誤:
Passkey 就是把密碼存在手機。正確:
Passkey 是公私鑰 credential,私鑰簽署 challenge,伺服器保存 public key。2. 不驗 challenge
錯誤:
credential id 存在就登入成功。正確:
必須驗 challenge、signature、origin、RP ID、UP/UV。3. 不驗 origin / RP ID
錯誤:
只要簽章正確就接受。正確:
簽章必須對應正確 origin 和 RP ID。4. 無密碼登入卻不要求 User Verification
錯誤:
Passkey 登入只要求 user presence。正確:
無密碼或高風險登入應要求 userVerification = required。5. 沒有 recovery
錯誤:
使用者只有一個 passkey,裝置遺失後無法恢復。正確:
提供第二 passkey、security key、backup codes 或安全恢復流程。6. 自己手寫 WebAuthn 驗證細節
錯誤:
自己解析 CBOR、COSE、attestation、authenticatorData。正確:
使用成熟 WebAuthn library,工程重點放在流程、資料模型、風險控制和 UX。十八、 面試追問題庫
Q1:Passkey 為什麼抗釣魚?
因為 Passkey credential 和 RP ID / origin 綁定。釣魚網站即使長得像真網站,也不是同一個 origin,無法讓使用者的 authenticator 對真網站 challenge 產生有效簽章。
Q2:WebAuthn 登入時伺服器驗證什麼?
伺服器要驗 challenge、origin、RP ID hash、credential id、簽章、user presence、user verification,以及 sign counter 等資訊。驗證成功後才建立本地 session。
Q3:Passkey 和 TOTP 差在哪?
TOTP 是 shared secret 加時間產生 OTP,使用者會輸入 code,因此可能被即時釣魚轉送。Passkey 是 public/private key challenge-response,私鑰不離開 authenticator,且 credential 綁定 RP ID / origin,因此更抗釣魚。
Q4:Passkey 是不是 MFA?
看情境。若搭配密碼使用,它是第二因素。若單獨用於無密碼登入,並且 authenticator 要求 user verification,則一次登入同時包含持有裝置和本機驗證因素。實務上要看 authenticator 類型、UV 設定和保證等級。
Q5:Platform authenticator 和 roaming authenticator 差在哪?
Platform authenticator 內建於裝置,例如 Touch ID、Face ID、Windows Hello,體驗好且常可同步。Roaming authenticator 是可攜式安全金鑰,例如 YubiKey,適合高安全場景。
Q6:Syncable passkey 有什麼風險?
Syncable passkey 體驗好,能降低換裝置遺失憑證的問題,但它信任平台同步機制。高風險或企業場景要評估同步安全、裝置管理、恢復流程和是否需要硬體安全金鑰。
Q7:為什麼伺服器只存 public key?
因為登入時只需要用 public key 驗證 authenticator 對 challenge 的簽章。private key 留在使用者 authenticator 裡,不送到伺服器,因此伺服器資料外洩時,public key 不能直接用來登入。
十九、 實作題
題目一:設計 Passkey 註冊流程
請描述:
- 使用者已登入。
- 要求近期重新驗證。
- 後端產生 registration challenge。
- 前端呼叫
navigator.credentials.create()。 - authenticator 產生 credential。
- 前端送 attestation response。
- 後端驗 challenge、origin、RP ID、UP/UV。
- 保存 credential id、public key、sign counter。
- 寄通知與 audit log。
題目二:設計 Passkey 登入流程
要求:
- 支援 discoverable credential。
- challenge 短效一次性。
- 驗證 origin / RP ID。
- 驗簽章。
- 更新 last_used_at。
- 建立本地 session。
- 高風險時要求 user verification。
題目三:設計資料表
請設計:
users
webauthn_credentials
webauthn_challenges
sessions
audit_logs要說明:
- credential id 唯一。
- public key 保存。
- sign counter 可選但要處理。
- challenge 有 purpose 與 expires_at。
- passkey 移除要 re-authentication。
二十、 資深視角
1. Passkey 把信任從「人記得秘密」轉到「裝置持有私鑰」
密碼的問題是:
秘密會被人輸入、重用、釣魚、外洩。Passkey 的設計是:
私鑰不離開 authenticator;
網站只驗簽章。這是身份驗證模型的根本改變。
2. Origin binding 是安全價值核心
Passkey 的重點不是方便,也不是生物辨識。
真正關鍵是:
credential 和正確網站綁定。這讓它天然抵抗大量釣魚攻擊。
3. Passwordless 不代表沒有風險
Passkey 很強,但系統仍要設計:
- 註冊保護。
- 移除保護。
- recovery。
- 多裝置。
- session。
- audit log。
- 高風險操作 fresh verification。
- 企業裝置政策。
如果恢復流程很弱,攻擊者仍會繞過正門。
4. 產品遷移要漸進
很多產品不能一口氣改成 passwordless。
比較務實的路線:
密碼登入 -> 鼓勵新增 passkey -> passkey 作為 MFA -> passkey-first -> passwordless同時保留:
- backup codes。
- TOTP。
- recovery。
- 管理員恢復。
讓使用者逐步升級,而不是一次把所有人丟進新模型。
總結
| 問題 | 回答重點 |
|---|---|
| Passkey | 基於公私鑰的登入憑證 |
| WebAuthn | W3C 瀏覽器 API |
| FIDO2 | WebAuthn + CTAP 的標準集合 |
| 核心 | challenge-response signature |
| 伺服器保存 | public key、credential id、counter |
| 私鑰 | 留在 authenticator 或同步系統 |
| 抗釣魚原因 | credential 綁定 RP ID / origin |
| Authenticator | platform 或 roaming |
| UV | 指紋、Face ID、PIN 等本機使用者驗證 |
| 風險 | recovery、同步模型、裝置遺失、實作錯誤 |
一句完整的面試回答可以是:
Passkey 是基於 WebAuthn / FIDO2 的公私鑰登入憑證。註冊時,瀏覽器透過 WebAuthn API 呼叫 platform authenticator 或 security key,為特定 RP ID 產生 credential,私鑰保存在使用者裝置或同步憑證管理系統中,伺服器只保存 credential id、public key、sign counter 等資料。登入時伺服器產生短效 challenge,authenticator 在使用者通過 user presence 或 user verification 後,用私鑰簽署 challenge,伺服器用 public key 驗證簽章,並檢查 challenge、origin、RP ID、UP/UV 等資訊。因為 credential 綁定網站 origin / RP ID,釣魚網站無法取得可用於真網站的簽章,所以 Passkey 比 SMS、Email OTP、TOTP 更具釣魚抗性。不過仍要設計註冊保護、移除保護、backup codes、recovery、session 與 audit log。