iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Security

『零信任』的革命:從 FIDO 協議到自動化部署,30天打造次世代身分認證系統系列 第 3

【Day 03 —協議詳解】WebAuthn 的世界觀:讀懂規格書的第一步

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250818/20151778DEIvHkz89d.png

前言:從宏觀地圖到微觀詞典

在昨天的探索中,我們繪製了一張 FIDO2 的宏觀作戰地圖,理解了 WebAuthn (軟體 API) 與 CTAP (硬體通訊) 如何協同作戰。今天,我們將暫時收起地圖,拿出放大鏡,聚焦在地圖上離我們開發者最近的核心區域——WebAuthn API

要讀懂任何一部經典,都必須先熟悉其中的角色與關鍵詞彙。WebAuthn 也不例外。在我們動手編寫任何程式碼之前,必須先建立一個清晰的「世界觀」,搞懂誰是誰、它們各自的職責,以及它們之間傳遞的「信物」代表什麼。

舞台上的核心角色 (Actors)

https://ithelp.ithome.com.tw/upload/images/20250818/201517788wXdRgs8Ik.png

WebAuthn 的運作就像一齣舞台劇,由三個核心角色協力完成一場關於「信任」的演出。

  1. 信賴方 (Relying Party, RP)

    • 角色定位:我們的應用程式後端伺服器。它是那個「想要驗證使用者身分」的服務,例如網路銀行、電商網站或任何需要登入的系統。
    • 核心職責:RP 是整個安全流程的大腦與決策者。
      • 出題者:為每一次的註冊與登入,都必須產生一個獨一無二、不可預測的隨機挑戰碼 (Challenge)
      • 驗證者:負責驗證由驗證器回傳的加密簽章與證明,確保其合法性。
      • 記錄者:安全地儲存使用者的公鑰及相關憑證資訊,以備未來登入時進行比對。
  2. 驗證器 (Authenticator)

    • 角色定位:一個能夠安全生成金鑰並執行簽章操作的硬體或軟體。它是安全性的最終堡壘,私鑰的守護者。
    • 核心職責
      • 在安全環境中(如 Secure Enclave, TPM)創建並儲存私鑰。
      • 在收到使用者授權後(例如透過指紋、人臉辨識或 PIN 碼),使用私鑰對挑戰進行簽章。
    • 區分類型
      • 平台驗證器 (Platform Authenticator):內建於使用者裝置中的驗證器,例如 Windows Hello、macOS 的 Touch ID 或 Android 的指紋感應器。它們與裝置緊密綁定。
      • 漫遊/跨平台驗證器 (Roaming/Cross-Platform Authenticator):可獨立於裝置使用的驗證器,通常透過 USB、NFC 或藍牙連接,例如 YubiKey、Google Titan 安全金鑰。它們提供了跨裝置使用的便利性。
  3. 客戶端 (Client)

    • 角色定位:協調 RP 與 Authenticator 之間的中介者,通常就是指網頁瀏覽器
    • 核心職責:Client 如同劇組的執行製作翻譯官,忠實地在導演(RP)和演員(Authenticator)之間傳遞訊息。
      • 透過 WebAuthn API (JavaScript) 接收來自 RP 的指令。
      • 透過 CTAP 協定將指令翻譯並傳達給驗證器。
      • 將驗證器回傳的結果,再透過 WebAuthn API 回報給 RP。

兩大核心儀式:註冊 (Attestation) 與驗證 (Assertion)

WebAuthn 的所有互動,都圍繞著這兩個核心的「儀式」展開。

1. 註冊儀式 (Attestation):信任的誕生

「Attestation」意為「證明」。這是在使用者帳戶與一個新的驗證器之間建立信任連結的過程。

API 呼叫流程:

  1. [RP] 後端伺服器產生一個包含隨機挑戰碼 (challenge) 與其他註冊選項的 options 物件。
  2. [RP -> Client] 後端將此 options 物件傳送給前端頁面。
  3. [Client] 前端的 JavaScript 呼叫 navigator.credentials.create({ publicKey: options }),將後端傳來的選項交給瀏覽器。
  4. [Client <-> Authenticator] 瀏覽器透過 CTAP 協定,提示使用者啟動驗證器(如觸摸指紋)。驗證器在內部生成一對新的公私鑰,並建立一個包含新公鑰的「證明物件 (Attestation Object)」。
  5. [Client -> RP] create() 函式成功後回傳一個 PublicKeyCredential 物件,前端將此物件送回後端進行驗證。
  6. [RP] 後端驗證此物件中的簽章與挑戰碼,確認無誤後,將公鑰使用者 ID 存入資料庫,完成註冊。

PublicKeyCredential
是在註冊與驗證過程中,WebAuthn API 回傳給我們網站的頂層資料容器。可以把它想像成一個公文袋,裡面裝著所有重要的文件。

// Day 03: 註冊儀式的前端呼叫範例

async function startRegistration() {
  // 步驟 1 & 2: 從我們的後端伺服器獲取註冊選項
  const response = await fetch('/generate-registration-options');
  const options = await response.json();

  // WebAuthn 要求 challenge 等二進位資料必須是 ArrayBuffer
  // 需要一個輔助函數來轉換 Base64URL 編碼的 challenge
  options.challenge = bufferDecode(options.challenge);
  options.user.id = bufferDecode(options.user.id);

  try {
    // 步驟 3: 呼叫 WebAuthn API,觸發瀏覽器與驗證器的互動
    const credential = await navigator.credentials.create({
      publicKey: options
    });

    // 步驟 5: 將瀏覽器回傳的憑證送回後端進行驗證
    await sendRegistrationToServer(credential);
    alert('註冊成功!');

  } catch (err) {
    console.error('註冊失敗:', err);
  }
}

2. 驗證儀式 (Assertion):信任的證明

「Assertion」意為「斷言」。這是使用者在登入時,向伺服器證明自己確實擁有私鑰的過程。

API 呼叫流程:

  1. [RP] 後端伺服器產生一個包含新隨機挑戰碼 (challenge)options 物件。
  2. [RP -> Client] 後端將此 options 物件傳送給前端頁面。
  3. [Client] 前端的 JavaScript 呼叫 navigator.credentials.get({ publicKey: options })
  4. [Client <-> Authenticator] 瀏覽器提示使用者啟動驗證器。驗證器使用之前註冊時儲存的私鑰,對新的挑戰碼進行簽章,產生一個「斷言 (Assertion)」。
  5. [Client -> RP] get() 函式成功後回傳 PublicKeyCredential 物件,前端將其送回後端。
  6. [RP] 後端從資料庫中找出該使用者的公鑰,用來驗證斷言中的簽章是否正確。驗證成功即代表登入成功。
// Day 03: 驗證儀式的前端呼叫範例

async function startLogin() {
  // 步驟 1 & 2: 從後端獲取登入選項
  const response = await fetch('/generate-authentication-options');
  const options = await response.json();

  options.challenge = bufferDecode(options.challenge);

  try {
    // 步驟 3: 呼叫 WebAuthn API,請求使用者進行簽章
    const assertion = await navigator.credentials.get({
      publicKey: options
    });

    // 步驟 5: 將簽章後的結果送回後端進行驗證
    await sendLoginAssertionToServer(assertion);
    alert('登入成功!');
    window.location.href = "/dashboard"; // 導向登入後頁面

  } catch (err) {
    console.error('登入失敗:', err);
  }
}

結語:為解構儀式做好準備

今天,我們沒有深入後端驗證的複雜細節,而是建立了一份至關重要的詞彙表與角色名單。我們認識了舞台上的三大主角:信賴方 (RP)驗證器 (Authenticator)客戶端 (Client),也清楚看見了它們在註冊 (Attestation) 與登入 (Assertion) 這兩大儀式中的 API 互動流程。

有了這些共同語言與清晰的流程概念,我們就做好了萬全的準備。

明天,我們將正式開始解構 WebAuthn 的第一個核心儀式——註冊 (Registration)。我們將使用序列圖 (Sequence Diagram) 來描繪這些角色如何互動,並深入探討後端伺服器(RP)在發起註冊請求與驗證註冊結果時,必須完成的每一個關鍵步驟。


參考資料:

  1. 使用 WebAuthn 實作無密碼驗證與 Passkey 介紹

上一篇
【Day 02 — FIDO 生態系】解構 FIDO2:WebAuthn、CTAP 與公鑰密碼學的交響樂
下一篇
【Day 04 —協議詳解 II】信任的誕生:解構 WebAuthn 註冊儀式
系列文
『零信任』的革命:從 FIDO 協議到自動化部署,30天打造次世代身分認證系統9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言