繁體中文(香港)
  • jwt
  • auth
  • authentication
  • identity
  • api
  • openid
  • oauth

JSON Web Token (JWT) 是什麼?

在 5 分鐘內清楚了解 JSON Web Token (JWT) 的基本知識。

Gao
Gao
Founder

Stop wasting weeks on user auth
Launch secure apps faster with Logto. Integrate user auth in minutes, and focus on your core product.
Get started
Product screenshot

JSON Web Token (JWT) 廣泛應用於現代網絡應用程式和開放標準例如 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 和網頁瀏覽器的 jose

總結

在這篇文章中,我們簡要地解釋了 JWT 的核心概念,以及如何創建和驗證它的概覽。許多細節尚未被探索,我們會在未來的文章中覆蓋它們。

Logto 利用像 JWT 和 OpenID Connect 的開放標準來通過簡化的工作流程保護你的應用程式和 API。若你感興趣,可以免費試用(不需要信用卡)。