跳至主要內容
Skip to content

Passkey、WebAuthn 與 FIDO2

Passkey 是近年身份驗證裡最重要的變化之一。

它想解決的不是:

text
把密碼變得更複雜。

而是:

text
讓使用者不再需要輸入可被釣魚、重用、外洩的密碼。

很多人第一次看到 Passkey 會以為:

text
這就是用指紋或 Face ID 登入。

這個說法只對了一半。

比較準確地說:

text
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 更好的釣魚抗性。

短一點可以說:

text
Passkey 不是把密碼存在裝置裡,
而是用網站專屬的私鑰簽署 challenge。

二、 名詞先拆開

名稱意義
Passkey使用者可感知的無密碼登入憑證,通常可同步
WebAuthnW3C 定義的瀏覽器 API 與資料結構
FIDO2FIDO Alliance 的標準集合,通常包含 WebAuthn + CTAP
CTAPClient to Authenticator Protocol,瀏覽器和 authenticator 溝通
Authenticator產生與保存私鑰的裝置或元件
Relying Party依賴 WebAuthn 驗證使用者的網站或服務
Credential某個 RP 下的一組公私鑰登入憑證

可以這樣理解:

text
WebAuthn:瀏覽器給網站用的 API。
CTAP:瀏覽器和安全金鑰 / 手機等 authenticator 溝通的協議。
FIDO2:WebAuthn + CTAP 這套公私鑰登入標準。
Passkey:建立在這些標準上的使用者體驗與憑證形式。

三、 Passkey 為什麼抗釣魚

傳統密碼和 OTP 的問題是:

text
使用者可以把它輸入到假網站。

例如:

text
真網站:example.com
假網站:examp1e.com

使用者看錯網址,把密碼和 TOTP 輸入假網站,攻擊者就能即時轉送到真網站。

Passkey 的關鍵差異是:

text
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:

text
private key:留在使用者 authenticator 裡
public key:交給伺服器保存

伺服器永遠不需要知道 private key。

登入時:

text
伺服器發 challenge
authenticator 用 private key 簽章
伺服器用 public key 驗簽

概念:

這和密碼最大的差別:

比較密碼Passkey
使用者輸入秘密不會
伺服器保存password hashpublic 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,代表使用者有做某個動作。

例如:

  • 觸碰安全金鑰。
  • 按下裝置確認。

它證明:

text
不是背景程式偷偷簽章,使用者有參與。

User Verification

User Verification,簡稱 UV,代表 authenticator 驗證了使用者本人。

例如:

  • 指紋。
  • Face ID。
  • 裝置 PIN。
  • Windows Hello。

它證明:

text
不只是有人按了裝置,而是通過本機解鎖驗證。

設定上常見:

ts
userVerification: 'preferred' | 'required' | 'discouraged'

高風險登入或無密碼登入通常會要求:

text
userVerification = required

因為如果只要求 presence,撿到安全金鑰的人可能只要按一下就能登入。

七、 註冊流程

註冊 Passkey 不是把密碼存起來。

它是讓 authenticator 為你的網站產生新 credential。

流程:

後端回給前端的是:

ts
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,驗證回來時確認它沒有被換掉。

八、 登入流程

登入時不傳密碼,而是驗簽。

流程:

重點:

text
伺服器不是驗證使用者輸入的秘密,
而是驗證 authenticator 對 challenge 的簽章。

九、 後端驗證重點

WebAuthn 驗證不能只看:

text
有回 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 包含:

text
scheme + host + port

例如:

text
https://app.example.com

RP ID

RP ID 通常是 domain:

text
example.com

或:

text
app.example.com

credential 會和 RP ID 綁定。

常見設計:

text
rp.id = example.com

這樣可允許:

text
app.example.com
admin.example.com

在同一 RP ID 下使用 credential,前提是 origin 驗證也正確。

但不能跨到:

text
evil-example.com

設定 RP ID 時要小心:

  • 本機開發環境。
  • 多子網域。
  • 多租戶 custom domain。
  • staging / production 分離。
  • mobile app deep link 或 native app。

不要為了方便把驗證放寬。

十一、 Discoverable Credential 與使用者名稱

Passkey 常支援「不用先輸入帳號」的登入體驗。

這依賴 discoverable credential,也常被稱為 resident key。

流程是:

text
使用者點 Passkey 登入
瀏覽器 / authenticator 顯示可用帳號
使用者選擇帳號
authenticator 回傳 credential
伺服器根據 credential id 找 user

如果不是 discoverable credential,使用者可能要先輸入 email,伺服器再給 allowCredentials。

兩種都可以:

類型體驗特點
Discoverable credential可無帳號輸入更像完整 passkey 體驗
Non-discoverable credential先輸入帳號較傳統,server 指定 credential

現代 Passkey 體驗通常會偏向 discoverable credential。

十二、 資料表設計

可以設計一張 webauthn_credentials

sql
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_idauthenticator 建立的 credential 識別
public_key伺服器用來驗簽
sign_count簽章計數,用於偵測 clone,視 authenticator 支援
transportsusb、nfc、ble、internal 等
backup_eligible是否可備份 / 同步
backup_state目前是否被備份
name使用者自訂名稱,例如 MacBook Touch ID
last_used_at最近使用時間

也要有 challenge store:

text
webauthn_challenges

保存:

  • user id 或 anonymous flow。
  • challenge。
  • purpose。
  • expires_at。
  • used_at。
  • rp_id。
  • expected_origin。

challenge 必須短效且一次性。

十三、 Passkey 是 MFA 還是 Passwordless?

答案要看它的使用方式與 authenticator。

Passkey 可以用在:

text
密碼 + Passkey

這時它是第二因素。

也可以用在:

text
Passkey only

這時它是無密碼登入。

如果 authenticator 要求 user verification,例如生物特徵或裝置 PIN,則一次登入中包含:

  • 持有因素:使用者控制私鑰裝置。
  • 知識或生物因素:PIN / biometric 解鎖本機私鑰。

所以平台 passkey 常被視為強身份驗證方式。

但實務上仍要看:

  • userVerification 是否 required。
  • authenticator 是否同步。
  • 是否允許多裝置。
  • 帳號恢復流程。
  • 企業政策。
  • 風險場景。

十四、 Syncable Passkeys

現代 Passkey 很多是可同步的。

例如:

  • iCloud Keychain 在 Apple 裝置間同步。
  • Google Password Manager 在 Android / Chrome 生態同步。
  • 密碼管理器同步 passkeys。

這大幅改善使用體驗:

text
換手機也不一定遺失 passkey。

但安全模型也和硬體安全金鑰不同。

硬體安全金鑰通常強調:

text
private key 不可匯出。

同步 passkey 則允許 key 在受保護的同步系統中跨裝置可用。

這不是壞事,但系統要理解差異:

類型優點風險/考量
Syncable passkey體驗好、不易因換裝置遺失信任平台同步安全
Hardware security key私鑰不可匯出、高安全成本、遺失、備援

NIST SP 800-63B 已納入 syncable authenticators 的相關要求與風險考量。產品設計時不要把所有 passkey 都當成同一種保證等級,尤其在企業或高風險場景。

十五、 Passkey 與 TOTP 比較

比較TOTPPasskey / WebAuthn
核心shared secret + timepublic/private key + challenge
伺服器保存encrypted secretpublic key
使用者輸入 code需要不需要
是否可被即時釣魚轉送可以因 origin/RP ID 綁定而困難
裝置遺失需要 backup / recovery同步 passkey 較好恢復,硬體 key 需備援
適合一般 MFA高安全、無密碼、釣魚抗性

TOTP 的問題是:

text
使用者可以把 code 輸入假網站。

Passkey 的優勢是:

text
簽章只對正確 RP / origin 有效。

這就是為什麼 Passkey 是下一代身份驗證的重要方向。

十六、 帳號恢復與備援

Passkey 很安全,但仍要處理:

text
裝置不見了怎麼辦?

備援方式:

  • 第二個 passkey。
  • 硬體安全金鑰。
  • Backup codes。
  • TOTP。
  • 已登入可信裝置。
  • 企業管理員恢復。
  • 高風險身份驗證。

不要只有一個 passkey。

好的設計會鼓勵:

text
至少新增兩個登入方式。

例如:

  • 手機 passkey。
  • 筆電 passkey。
  • backup code。

高風險帳號可要求:

  • 至少兩個 security keys。
  • 或 passkey + hardware key。

十七、 常見錯誤

1. 以為 Passkey 是存密碼

錯誤:

text
Passkey 就是把密碼存在手機。

正確:

text
Passkey 是公私鑰 credential,私鑰簽署 challenge,伺服器保存 public key。

2. 不驗 challenge

錯誤:

text
credential id 存在就登入成功。

正確:

text
必須驗 challenge、signature、origin、RP ID、UP/UV。

3. 不驗 origin / RP ID

錯誤:

text
只要簽章正確就接受。

正確:

text
簽章必須對應正確 origin 和 RP ID。

4. 無密碼登入卻不要求 User Verification

錯誤:

text
Passkey 登入只要求 user presence。

正確:

text
無密碼或高風險登入應要求 userVerification = required。

5. 沒有 recovery

錯誤:

text
使用者只有一個 passkey,裝置遺失後無法恢復。

正確:

text
提供第二 passkey、security key、backup codes 或安全恢復流程。

6. 自己手寫 WebAuthn 驗證細節

錯誤:

text
自己解析 CBOR、COSE、attestation、authenticatorData。

正確:

text
使用成熟 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 註冊流程

請描述:

  1. 使用者已登入。
  2. 要求近期重新驗證。
  3. 後端產生 registration challenge。
  4. 前端呼叫 navigator.credentials.create()
  5. authenticator 產生 credential。
  6. 前端送 attestation response。
  7. 後端驗 challenge、origin、RP ID、UP/UV。
  8. 保存 credential id、public key、sign counter。
  9. 寄通知與 audit log。

題目二:設計 Passkey 登入流程

要求:

  • 支援 discoverable credential。
  • challenge 短效一次性。
  • 驗證 origin / RP ID。
  • 驗簽章。
  • 更新 last_used_at。
  • 建立本地 session。
  • 高風險時要求 user verification。

題目三:設計資料表

請設計:

text
users
webauthn_credentials
webauthn_challenges
sessions
audit_logs

要說明:

  • credential id 唯一。
  • public key 保存。
  • sign counter 可選但要處理。
  • challenge 有 purpose 與 expires_at。
  • passkey 移除要 re-authentication。

二十、 資深視角

1. Passkey 把信任從「人記得秘密」轉到「裝置持有私鑰」

密碼的問題是:

text
秘密會被人輸入、重用、釣魚、外洩。

Passkey 的設計是:

text
私鑰不離開 authenticator;
網站只驗簽章。

這是身份驗證模型的根本改變。

2. Origin binding 是安全價值核心

Passkey 的重點不是方便,也不是生物辨識。

真正關鍵是:

text
credential 和正確網站綁定。

這讓它天然抵抗大量釣魚攻擊。

3. Passwordless 不代表沒有風險

Passkey 很強,但系統仍要設計:

  • 註冊保護。
  • 移除保護。
  • recovery。
  • 多裝置。
  • session。
  • audit log。
  • 高風險操作 fresh verification。
  • 企業裝置政策。

如果恢復流程很弱,攻擊者仍會繞過正門。

4. 產品遷移要漸進

很多產品不能一口氣改成 passwordless。

比較務實的路線:

text
密碼登入 -> 鼓勵新增 passkey -> passkey 作為 MFA -> passkey-first -> passwordless

同時保留:

  • backup codes。
  • TOTP。
  • recovery。
  • 管理員恢復。

讓使用者逐步升級,而不是一次把所有人丟進新模型。


總結

問題回答重點
Passkey基於公私鑰的登入憑證
WebAuthnW3C 瀏覽器 API
FIDO2WebAuthn + CTAP 的標準集合
核心challenge-response signature
伺服器保存public key、credential id、counter
私鑰留在 authenticator 或同步系統
抗釣魚原因credential 綁定 RP ID / origin
Authenticatorplatform 或 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。

延伸閱讀