不透明 Token 與 JWT
理解不透明 token 與 JWT 的差異、它們的使用情境,以及它們在基於 OIDC 的系統中如何驗證。
在 Logto 作為一個基於 OIDC 的綜合 CIAM 平台中,授權 token 在保障用戶互動安全和管理資源訪問方面發揮著關鍵作用。在用於授權的各種 token 中,不透明 token 和 JWT(JSON Web Tokens)是最重要的。
我們收到了社區的幾個問題,例如:不透明 token 和 JWT 有什麼區別?為什麼我無法解碼收到的存取 token,為什麼 token 的長度看起來很短?這篇文章旨在澄清這些概念,並幫助你理解不透明 token 和 JWT 之間的區別,它們的使用情境,以及為什麼在使用它們時可能會遇到不同的行為。
什麼是不透明 token?
不透明 token 是一種類型的存取 token,正如名稱所示,對於客戶端或任何外部方都是不透明或非透明的。這意味著 token 本身不承載任何用戶或授權信息的可讀內容。
當你收到一個不透明 token 時,它通常顯示為一個看似隨機的字元串,試圖解碼它不會獲得任何有意義的數據。
這是一個不透明 token 的例子:
由於 token 的實際內容只有簽發它的授權伺服器知道,要驗證一個不透明 token,客戶端必須將其發回伺服器,然後伺服器驗證其真實性並確定相關的許可。這種方法確保敏感信息保持隱藏,提供了一層額外的安全性,但也需要額外的伺服器通信來驗證 token。
優點:
- 安全:不透明 token 不向客戶端公開任何敏感信息。token 的內容只有授權伺服器知道。
- 可撤銷:由於 token 儲存在伺服器上,且驗證它的唯一方法是通過授權伺服器上的內省端點,伺服器可以輕鬆撤銷 token 並防止未授權的訪問。
- 小尺寸:不透明 token 通常比 JWT 短,這對性能和存儲考量是有利的。
缺點:
- 有狀態:不透明 token 需要授權伺服器維持狀態來驗證 token,這可能會增加複雜性和負擔。
- 性能:需要額外的伺服器通信來驗證 token,可能會影響性能,尤其是在高流量場景中。
什麼是 JWT?
與不透明 token 相比,JWT(JSON Web Token)是一個自包含的、無狀態的 token,以結構化和可讀格式承載信息。
一個 JWT 由三部分組成:header
、payload
和 signature
,每一部分都用 Base64URL 編碼。
這是一個 JWT 的例子:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
header
包含有關 token 類型和簽名算法的信息。例如,{"alg": "HS256", "typ": "JWT"}
。payload
部分包含 claim——有關用戶或授權的信息片段,如用戶 ID、過期時間和 scope。由於這些數據是編碼的但不是加密的,任何擁有 token 的人都可以解碼它以查看 claims,雖然他們無法更改它而不使簽名無效。根據規範和授權伺服器配置,可以在 payload 中包含各種 claims。這給了 token 其自包含的特性。例如,{"sub": "1234567890", "name": "John Doe", "iat": 1516239022}
。signature
透過使用指定的算法將 header、payload 和一個密鑰結合而生成。此簽名用於驗證 token 的完整性,確保它未被篡改。
JWT 被廣泛使用,因為它們可以在本地由客戶端或任何服務驗證,而不需要與授權伺服器互動。這使得 JWT 對於分佈式系統特別高效,在這樣的系統中,多個服務可能需要獨立驗證 token 的真實性。
然而,這種方便性也伴隨著確保 token 的 claims 不過度曝光的責任,因為這些 claims 是對任何有權限取得 token 的人可見的。此外,JWT 通常是短命的,其過期時間包含在 token 的 claims 中,以確保 token 不會無限期有效。
優點:
- 無狀態:JWT 是自包含的,無需伺服端狀態即可驗證。
- 跨服務兼容性:JWT 可以輕鬆在不同服務間共享和驗證,是分佈式系統的理想選擇。
- 可擴展:JWT 的 payload 可以包含自定義的 claims,允許靈活的授權和信息共享。
- 標準化:JWT token 遵循一個定義良好的標準(RFC 7519),使得它們廣泛支持且可互操作。
缺點:
- 曝光:JWT 中的 claims 對任何有 token 訪問權限的人都是可見的,因此不應該在 payload 中包含敏感信息。
- 大尺寸:由於攜帶了附加信息,JWT 通常比不透明 token 更大,這可能會影響性能和存儲考量。JWT token 的 claims 應儘量減少以降低 token 的大小。
- 撤銷複雜性:由於 JWT 是無狀態的,通常僅在短時間內有效,並且沒有內建的機制在其過期前撤銷 token,這意味著被侵害的 token 可能會在到期前仍然有效。
不透明存取 token 的驗證
不透明存取 token 是透過將其發回授權伺服器進行驗證的。授權伺服器維護已發布 token 的狀態,可以根據其內部存儲確定 token 的有效性。
- 客戶端從授權伺服器請求存取 token。
- 授權伺服器發出一個不透明 token。
- 客戶端使用不透明 token 發送資源存取請求。
- 資源提供者向授權伺服器發送 token 內省請求以驗證 token。
- 授權伺服器回應 token 的資訊。
JWT 存取 token 的驗證(離線)
JWT 存取 token 可以由擁有 token 公鑰的客戶端或任何服務離線驗證。
- 資源提供者從 OIDC 發現端點預取授權伺服器的公鑰。公鑰用來驗證 token 的簽名並確保其完整性。
- 客戶端從授權伺服器請求存取 token。
- 授權伺服器發出一個 JWT token。
- 客戶端使用 JWT token 發送資源存取請求。
- 資源提供者解碼並使用從授權伺服器獲得的公鑰驗證 JWT token。
- 資源提供者基於 token 的有效性授予存取權限。
在 OIDC 中的使用情境
在 OIDC(OpenID Connect)的語境中,不透明 token 和 JWT服務於不同的目的,並在不同情境中使用。
不透明 token
- 用戶資料檢索:
在未指定資源並包括 openid
scope 的情況下,當一個客戶端請求一個存取 token 時,授權伺服器默認簽發一個不透明存取 token。這個 token 主要用於從 OIDC 的 /oidc/userinfo
端點檢索用戶資料信息。當收到帶有不透明存取 token 的要求時,授權伺服器會檢查其內部存儲以檢索相關的授權信息,並驗證 token 的有效性後回應用戶資料詳情。
- 刷新 token 交換:
刷新 token 設計為僅在客戶端和授權伺服器之間交換,無需與資源提供者共享。因此,刷新 token 通常發行為不透明的 token。當當前的存取 token 過期時,客戶端可以使用不透明的刷新 token 獲取新存取 token,從而在不重新驗證用戶的情況下保持連續訪問。
JWTs
- ID token:
在 OIDC 中,ID token 是一個包含用戶信息的 JWT,並用於驗證用戶。通常在發放存取 token 的同時提供,ID token 允許客戶端驗證用戶的身份。例如:
客戶端可以驗證 ID token 以確保用戶身份,並提取用戶信息以進行個性化處理或授權目的。ID token 是一次性使用的,不應用於 API 資源授權。
- API 資源存取:
當一個客戶端請求一個具有特定資源指示的存取 token 時,授權伺服器簽發一個用於存取該資源的 JWT 存取 token。JWT 包含資源提供者可以用來授權客戶端訪問的 claims。例如:
資源提供者可以透過檢查以下 claims 驗證請求:
iss
:確認 token 由可信的授權伺服器簽發。sub
:識別與 token 相關的用戶。aud
:確保 token 是為了特定資源。scope
:驗證授予用戶的許可。
結論
總之,在基於 OIDC 的系統中,不透明 token 和 JWT 用於不同的目的,不透明 token 提供了一種安全且有狀態的授權方法,而 JWT 提供了一個自包含且無狀態的替代方案。了解這些 token 類型的區別及其使用情境對於設計安全且高效的身份驗證和授權機制至關重要。
在 Logto 中發掘更多存取 token 的功能: