憑證管理揭秘:Cookie-Session 與 JWT 方案的對決

肖卫卫讲编程發表於2024-04-25

概述

在上一篇文章我們聊完了授權的過程,在伺服器對客戶端完成授權之後,伺服器會給客戶端頒發對應的憑證,客戶端持有該憑證訪問服務端,伺服器便能知道你是誰,你有什麼許可權等資訊。這一章我們具體聊聊常見的憑證管理技術有哪些。

在軟體架構中,關於憑證如何儲存和傳遞,一直有兩種不同的解決思路,兩種不同的解決方式,實際上反映了兩種不同的架構思路:

  1. 一種是把所有狀態資訊都放在伺服器端 (Cookie-Session 方案)
  2. 一種是把所有狀態將資訊儲存在客戶端(JWT 方案)

在網際網路早期,這個問題早就有了明確的答案。大多數應用都採用了 “Cookie-Session” 的方法,這種方法透過在伺服器上儲存使用者狀態,來實現使用者身份的識別和資訊的傳遞。這種方法在很長一段時間裡都是主流。

然而,隨著微服務和分散式系統的興起,我們發現由於 CAP 的限制,伺服器端儲存狀態資訊的方式開始面臨很多問題(微服務要求服務端本身是無狀態,才能實現動態擴縮容)。這就迫使我們重新考慮被放棄的客戶端狀態儲存方法。在這個背景下,JWT(JSON Web Token)的令牌的方案開始受到關注。JWT 是一種在客戶端儲存使用者狀態資訊的方式,它允許使用者在不同的伺服器之間自由切換,而不需要重新登入。這種特性在分散式系統中非常有用。但是要明白,JWT 和 Cookie-Session 只是對授權資訊儲存的主體(客戶端,服務端)不同,各有優勢,合適場景不同,不存在誰比誰要先進的問題。在本節中,我們將探討 Cookie-Session 和 JWT 兩種方案的相同點和不同點,幫你更好地理解這兩種方案的優缺點,以及它們在不同場景下的應用。

總所周知,因為 HTTP 是無狀態協議,所以 Cookie-Session 的原理其實很簡單,就是解決 HTTP 協議無狀態的問題,在 RFC 6265 中定義了 HTTP 的狀態管理機制,增加 Set-Cookie 指令,服務端向客戶端傳送一組資訊(標識)示例:

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: session_token=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT; Path=/

客戶端收到指令後在此後一段時間的 HTTP 請求中都發給服務端會話資訊(在 Header 中攜帶 cookie 資訊),以便伺服器區分不同的客戶端:

GET /profile HTTP/1.1
Host: www.example.com
Cookie: sessionid=xyzasdzxc123789456

客戶端的 Cookies 裡通常只儲存一個無意義,不重複的字串,通常命名是 sessionidjessionid ,服務端則根據該字串作為 Key,和使用者資訊建立關聯後儲存在服務端的記憶體或者快取中。再輔以一些超時自動清理的措施來管理會話。

它們的互動過程如下:

cookie-session

這種服務端的狀態管理機制就是 Session,Cookie-Session 也是最傳統,但今天依然廣泛應用於大量系統中的,由服務端與客戶端聯動來完成的狀態管理機制。

總結

cookie-session 的方案在儲存授權資訊具有以下優勢:

  1. 安全性:由於狀態資訊都儲存在服務端,cookie-session 方案在安全性上有天然的優勢,能完全規避上下文資訊在傳輸過程中被篡改的風險
  2. 靈活性:由於儲存在服務端,服務端可以儲存各種資料物件,而不僅僅是字串
  3. 狀態控制:服務端維護狀態的優勢在於可以根據自己的意願隨時修改,清除上下文資訊,可以很輕鬆實現使用者強制下線的功能。

Cookie-Session 在單體服務環境中是最合適的方案,但是因為服務端有狀態,當需要水平擴充套件服務能力,要部署叢集時就開始面臨麻煩了。接下來的 JWT 令牌就是 Cookie-Session 在分散式環境的替代品,但是不能說 JWT 要比 Cookie-Session 更加先進,更不可能全面取代 Cookie-Session 機制。

JWT

當服務端有多臺,並且不能儲存狀態的時候,客戶端就要承擔儲存有狀態(授權資訊)的職責了。這就是 JWT 令牌的方案思路。

JWT(JSON Web Token)是一種定義在 RFC 7519 標準中的令牌格式,主要應用於現代分散式應用系統中,經常與 OAuth2 協議配合使用。在深入探討 JWT 的結構之前,我們先來直觀地瞭解一下它的基本形式。示例:

jwt-info

注意:JWT 令牌不加密,只使用 Base64URL 轉碼,所以 JWT 令牌裡別放敏感資訊,令牌只解決防篡改的問題,並不解決防洩漏的問題,JWT 令牌都可以在 JWT 官網(https://jwt.io)上進行解碼。如圖所示,JWT(JSON Web Token)由三部分組成:Header(頭部)、Payload(負載)、Signature(簽名)。這三部分之間使用點(.)分隔。

Header:Header 部分通常包含令牌的型別(通常是 JWT)和使用的加密演算法,例如 HS256

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload:Payload 部分包含所需的宣告,這些宣告可以包括使用者資訊或其他相關資料。例如,使用者ID和過期時間:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 1516242622
}

負載部分,JWT 在 RFC 7519 中推薦(非強制約束)了七項宣告名稱(Claim Name),如有需要用到這些內容,建議欄位名與官方的保持一致:

  • iss(Issuer):簽發人。
  • exp(Expiration Time):令牌過期時間。
  • sub(Subject):主題。
  • aud (Audience):令牌受眾。
  • nbf (Not Before):令牌生效時間。
  • iat (Issued At):令牌簽發時間。
  • jti (JWT ID):令牌編號。

此外在 RFC 8225、RFC 8417、RFC 8485 等規範文件,以及 OpenID 等協議中,都定義有約定好公有含義的名稱,可以參考 IANA JSON Web Token Registry

Signature:Signature 是使用 Header 中指定的演算法和一個金鑰對 Header 和 Payload 進行簽名得到的。對前面兩部分內容進行加密計算,以例子裡使用的 JWT 預設的 HMAC SHA256 演算法為例,將透過以下公式產生簽名值:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload) , secret)

簽名的意義在於確保負載中的資訊是可信的、沒有被篡改的,也沒有在傳輸過程中丟失任何資訊。因為被簽名的內容哪怕發生了一個位元組的變動,也會導致整個簽名發生顯著變化。JWT 預設使用的 HMAC SHA256 演算法是一種金鑰雜湊演算法,適用於單體應用中,因為加密和驗證都需要由同一授權服務完成。在多方或分散式應用中,通常使用非對稱加密演算法進行簽名。這種情況下,授權服務使用私鑰簽名,並透過遵循 JSON Web Key 規範公開一個公鑰。這個公鑰用於驗證簽名,使其他服務能夠獨立驗證 JWT 的真實性,無需直接與授權服務通訊。

JWT 令牌的互動流程如下:

jwt-process

說明:如果是在分散式環境下,通常會有單獨的認證伺服器來負責頒發令牌。

傳送令牌

按照 HTTP 協議的規範,客戶端可以透過多種方式使用 HTTP 協議傳送 JWT 令牌給服務端。最標準的方式是將 JWT 放在 HTTP 的 Authorization 頭部中,通常與 Bearer 方案一起使用。這種方法簡單且符合 RESTful API 的最佳實踐:

GET /api/resource HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIx......

總結

JWT 令牌是分散式系統下憑證載體的優秀解決方案,它優點眾多:

  1. 解決了分散式系統下的狀態資訊的管理問題,讓服務端無狀態,實現動態擴縮容。
  2. 結構簡單,輕量,憑證本身包含重要資訊,服務端無需再查詢資料庫
  3. 透過金鑰對和簽名的方式,保證憑證資訊的無法被篡改,保證了憑證的真實性

但是沒有完美的解決方案,cookie-session 的優點也 JWT 也缺點:

  1. 會話難以主動失效:服務端難以登出令牌,如果非要實現,就要把狀態資訊轉移儲存到 redis 中。
  2. 攜帶的資訊有限:雖然 HTTP 沒有限制 Header 中可儲存的大小限制,但是 HTTP 服務端大多都有儲存上限,例如 tomcat 限制 8kb,nginx 限制 4kb
  3. 客戶端令牌洩露風險:客戶端令牌存在哪裡 ? Cookie ? localStrong ? Indexed ? 存在哪裡都有洩露風險。只要拿到令牌就能冒認客戶端身份
  4. 服務端無狀態會導致很多常見的功能難以實現,例如:踢人下線,統計線上人數等等。。

相關文章