實作密碼金鑰登入的筆記

程式技術

前陣子為了幫自己的部落格加入密碼金鑰登入的功能,花了一些時間去了解密碼金鑰背後的運作原理。趁著自己還記憶猶新的時候,我想寫一篇文章記錄一下這次學到的密碼金鑰概念,主要是針對專有名詞與驗證流程進行說明。

什麼是密碼金鑰(Passkey)?

密碼金鑰是一種新型的身份驗證方法,目的在取代傳統的密碼驗證。

它基於非對稱加密技術,使用一組金鑰對(Key Pair)來進行身份驗證:一個公開金鑰(數位憑證)和一個私密金鑰。用戶可以使用驗證裝置(手機、電腦或 Yubikey),向網站(信賴方)註冊密碼金鑰。驗證裝置會產生一對公私鑰,公鑰會儲存在網站的伺服器上,以便將來驗證的時候使用,私鑰則會安全的儲存在驗證裝置上。

因為私鑰從頭到尾都不會離開用戶的驗證裝置,即使伺服器遭到攻擊,攻擊者也無法獲取用戶的私鑰。

密碼金鑰的優點?

你不需要記住密碼,也不需要定期變更密碼。攻擊者如果想要假冒你的身份存取受限的數位資源,就必須「物理」上竊取你的驗證裝置。即使裝置真的被偷了,我們也能很直觀的發現(就像是你發現身上的鑰匙搞丟了),不像密碼往往是等到數位資源被盜取後才發現。

除此之外,我個人認為密碼金鑰最讚的點,就是無密碼登入能提供更為舒適的用戶體驗。

2025_04_19_22_57_41_8d331687f30f.gif
無密碼登入相當便捷,也能夠提升用戶體驗

認識密碼金鑰的標準與角色

當初在研究密碼金鑰如何實作時,我被一堆相關的專有名詞搞得頭昏眼花。這裡簡單的說明密碼金鑰中的角色與它們間會使用到的標準:

  • WebAuthn API:是一個網路標準,讓網站能使用公開金鑰密碼學來註冊和驗證使用者,而無需依賴傳統密碼。目前大多數瀏覽器都已支援 WebAuthn API。

    // 你可以使用下面 JavaScript 程式碼來檢查瀏覽器是否支援 WebAuthn API
    // 注意瀏覽器只允許你在有 HTTPS 的情況下使用 WebAuthn API
    window.PublicKeyCredential
  • CTAP:全稱為 Client to Authenticator Protocol ,即「客戶端到身份認證裝置協議」。它描述了客戶端(例如瀏覽器、作業系統或應用程式)如何與驗證裝置(例如 YubiKey)進行通訊,以執行身份驗證操作。
  • FIDO2:是使用者驗證的開放標準,目的在加強使用者對線上服務的登入方式。由 FIDO(Fast IDentity Online)聯盟與全球資訊網協會(W3C)共同完成的專案。現在可以當作是 WebAuthn API 和 CTAP2 通訊協定的統稱。
  • Relying Party:信賴方。也就是你的網路或行動應用程式。如果有一個網站提供 WebAuthn API 來註冊與驗證用戶的密碼金鑰,那麼這個網站就是一個信賴方。

    2025_04_19_21_56_37_0d6b80c2dd24.png
    提供密碼金鑰註冊與登入的網站即是信賴方
  • Authenticator:使用者的驗證裝置。是一種可以生成公鑰憑證並交由信賴方註冊的加密實體。驗證裝置又可以分為漫遊(Roaming)與平台(Platform)兩大類型。漫遊類型如 YubiKey 這種 USB 裝置,可以「漫遊」在不同的設備上使用。平台類型則綁定設備,例如你的手機、電腦與平板,這些設備上因為具備安全晶片,所以能夠當作驗證裝置來使用。

    2025_04_21_20_07_35_66fd077f73a3.jpg
    Yubico 推出的 YubiKey 為一種「漫遊」類型的實體驗證裝置
  • Discoverable Credential:可探索的憑證,舊稱為駐留金鑰 (Resident Key)。是一組包含公私鑰的金鑰對,公鑰由信賴方儲存,私鑰會儲存在驗證裝置上。支援可探索憑證的裝置,可以在不知道憑證 ID 的情況下進行驗證,用戶體驗上會更好。目前大多數新型驗證裝置都支援可探索憑證 ,例如密碼管理工具或新式 YubiKey。

與可探索的憑證相對應的,就是非探索的憑證(Non-Discoverable Credential)。驗證裝置不會儲存憑證,因此需要對裝置提供憑證 ID 來進行驗證。

更詳細的非探索憑證說明,可以參考黑大的這篇文章 - WebAuthn 無密碼登入不等於 Passkey

這些專有名詞可能會讓你感覺很複雜,但 Yubico 有一張圖可以很清楚明瞭的呈現這些名詞之間的關係。

2025_04_15_13_07_01_fc6ba0b61466.png
清楚說明密每個角色之間是用什麼協議進行溝通

密碼金鑰的註冊與身分驗證的流程

介紹完了密碼金鑰中的標準與角色,我們來看看在密碼金鑰的註冊與驗證過程中,前端(客戶端)與後端(信賴方)是如何進行溝通的。

註冊密碼金鑰的流程

  1. 前端向後端取得憑證建立選項(Credential Creation Options),開始註冊流程。
  2. 前端使用 WebAuthn API 呼叫驗證裝置,讓裝置根據選項產生一組金鑰對:公開金鑰憑證與私密金鑰。
  3. 前端會將新出爐的憑證傳送至後端。
  4. 後端會對憑證進行證明(Attestation),如果證明通過,會將憑證與相關資訊儲存在資料庫中,以供未來驗證用戶身份時使用。

當用戶註冊新的密碼金鑰後,建議發送信件通知用戶有新註冊的密碼金鑰。

身分驗證的流程

  1. 前端向後端取得憑證請求選項(Credential Request Options),開始身分驗證程流程。
  2. 前端使用 WebAuthn API 呼叫驗證裝置,讓裝置使用儲存在其中的私鑰,根據選項產生公開金鑰憑證。
  3. 前端將憑證傳送至後端。
  4. 後端會對憑證進行斷言(Assertion),並檢查憑證是否存在於資料庫中,如果存在就將對應的用戶進行登入。

當用戶註冊密碼金鑰後,就不應該允許用戶使用密碼登入。用戶可以使用密碼金鑰直接登入,或是搭配傳統密碼做多因素驗證。

密碼金鑰的缺點

我個人在使用密碼金鑰上沒有感受到什麼不便,但是我覺得 DHH 的文章 — Passwords have problems, but passkeys have more 相當值得一看。

因為使用密碼金鑰就代表將網站驗證與用戶的驗證裝置綁在一起,如果用戶忘記帶裝置,那麼他就無法登入網站。舉個簡單的例子,假設一位用戶在網站的引導下使用 Windows 設備建立密碼金鑰,那麼他在 iPhone 上想登入網站就會卡住,這對一般大眾來說可能會造成疑惑,畢竟不是每個人都會使用密碼管理工具。

不建議在網站上只註冊一個密碼金鑰,如果密碼金鑰遺失就很頭痛了,會無法登入網站。

所以 DHH 認為密碼金鑰也有缺點,使用密碼加上信箱的雙因素驗證對用戶來說更為直觀。但這些缺點就見仁見智了,沒有絕對的對與錯,我想好的用戶引導或許能避免上述提到的缺點,。

結語

本篇文章為實作密碼金鑰登入時所學到的知識點,希望能幫上同樣想在自己網站上實作密碼金鑰登入的你。下一篇文章預計來寫如何在 Laravel 中實作密碼金鑰登入。

參考資料

sharkHead
written by
sharkHead

持續努力中的後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言
新增留言
編輯留言