繁體中文(台灣)
  • jwt
  • auth
  • authentication
  • identity
  • api
  • openid
  • oauth

JSON Web Token (JWT) 是什麼?

在 5 分鐘內清楚理解 JSON Web Token (JWT) 的基本概念。

Gao
Gao
Founder

不要在使用者認證上浪費數週時間
使用 Logto 更快地發布安全應用程式。幾分鐘內整合使用者認證,專注於您的核心產品。
立即開始
Product screenshot

JSON Web Token (JWT) 在現代 web 應用程式和開放標準(如 OpenID Connect)中被廣泛使用,用於促進驗證和授權。雖然官方 RFC 7519 是一個重要的參考資料,但對初學者來說可能很難理解。在本文中,我們將專注於 JWT 的核心概念,並用簡單的語言和範例來呈現。

為什麼需要 JWT?

如今,在兩方之間使用 JSON 來交換數據已經相當常見。考慮一個表示使用者的 JSON 物件:

sub 是 "subject" 的縮寫,在 OpenID Connect 中是一個 標準聲明,用於表示用戶標識符(用戶 ID)。

我們如何保證這個 JSON 物件的 完整性?換句話說,我們如何確保數據在傳輸過程中沒有被篡改?一個常見的解決方案是使用數字簽名。例如,我們可以使用 公鑰加密:伺服器用它的私鑰對 JSON 物件進行簽名,客戶端可以用伺服器的公鑰驗證該簽名。

簡而言之,JWT 提供了一種標準化的方法來表示 JSON 物件及其簽名。

JWT 的格式

由於用於創建數字簽名的算法有很多種,因此有必要指定用於 JWT 簽名的算法。這是透過構建一個 JSON 物件來完成的:

alg 是 "algorithm" 的縮寫,typ 是 "type" 的縮寫。

通常,typ 被設定為大寫的 JWT。在我們的範例中,algHS256,代表 HMAC-SHA256(我們稍後會解釋),表示我們正在使用這個算法來創建簽名。

現在,我們擁有了創建 JWT 的所有要素:

  • 標頭 JSON:算法和類型
  • 載荷 JSON:實際數據
  • 簽名:涵蓋標頭和載荷的簽名

然而,某些字符如空格和換行符對網路傳輸不友好。因此,標頭和載荷需要進行 Base64URL 編碼。典型的 JWT 看起來像這樣:

. 用作分隔符。

讓我們把所有部分組合起來創建一個 JWT:

標頭

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

Base64URL 編碼: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

載荷

JSON: {"sub":"foo","name":"John Doe"}

Base64URL 編碼: eyJzdWIiOiJmb28iLCJuYW1lIjoiSm9obiBEb2UifQ

簽名

在 HMAC-SHA256 中,簽名是用密鑰創建的:

例如,密鑰是 some-great-secret,簽名就成為:XM-XSs2Lmp76IcTQ7tVdFcZzN4W_WcoKMNANp925Q9g

JWT

最終的 JWT 是:

任何擁有密鑰的一方都可以驗證這個有效的 JWT。

選擇簽名算法

如前所述,用於創建數字簽名的算法有多種。我們使用了 HS256 作為範例,但它可能不夠強,因為密鑰必須在雙方之間共享(例如,客戶端和伺服器)。

在現實場景中,客戶端可能包括像 React 應用這樣的公眾應用,這些應用無法保證密鑰的安全。因此,首選的方法是使用公鑰加密(即非對稱加密)來簽署 JWT。讓我們從最受歡迎的算法開始:RSA

RSA

RSA 是一種非對稱算法,它使用一對密鑰:一個公鑰和一個私鑰。公鑰用來驗證簽名,私鑰用來簽名。

RSA 的標頭 JSON 如下所示:

RS256 代表 RSA-SHA256,表示簽名是使用 RSA 算法和 SHA256 哈希函數創建的。你還可以使用 RS384RS512 來創建使用 SHA384 和 SHA512 哈希函數的簽名。

簽名是用私鑰創建的:

同樣,我們可以組合這些部分來創建一個 JWT,最終的 JWT 看起來像這樣:

現在,客戶端可以在不知道私鑰的情況下驗證簽名。

ECDSA

儘管 RSA 被廣泛採用,但它的簽名大小較大,有時甚至超過標頭和載荷的總大小。橢圓曲線數字簽名算法(ECDSA)是另一種非對稱算法,可以創建更緊湊的簽名,並且效能更高。

要為 ECDSA 生成私鑰,我們需要選擇一個曲線。這超出了本文的範疇,但你可以在 這裡 找到更多資訊。

ECDSA 的標頭 JSON 如下所示:

ES256 代表 ECDSA-SHA256,表示簽名是使用 ECDSA 算法和 SHA256 哈希函數創建的。你還可以使用 ES384ES512 來創建使用 SHA384 和 SHA512 哈希函數的簽名。

簽名是用私鑰創建的:

最終的 JWT 保留了與 RSA 相同的結構,但簽名顯著縮短:

驗證 JWT

驗證 JWT 是創建 JWT 的逆過程,簡單明瞭:

  1. 使用 . 分隔符將 JWT 分為三部分(標頭、載荷和簽名)。
  2. 使用 Base64URL 解碼標頭和載荷。
  3. 使用標頭中指定的算法和公鑰(對於非對稱算法)驗證簽名。

有許多庫可以協助 JWT 驗證,比如用於 Node.js 和 Web 瀏覽器的 jose

結論

在本文中,我們簡要說明了 JWT 的核心概念,以及如何創建和驗證它的概覽。仍有許多細節尚未探討,我們將在未來的文章中覆蓋這些內容。

Logto 利用 JWT 和 OpenID Connect 等開放標準透過簡化的工作流程來保護你的應用程式和 API。 如果你有興趣,可以試用免費版本(不需要信用卡)。