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

JSON Web Token (JWT) 是什麼?

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

Gao
Gao
Founder

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。 如果你有興趣,可以試用免費版本(不需要信用卡)。