JSON Web Token
| 狀態 | 擬議標準 |
|---|---|
| 首次出版 | 2010年12月28日 |
| 最新版本 | RFC 7519 2015年5月 |
| 組織 | 互聯網工程任務組 |
| 委員會 | 互聯網工程指導組 |
| 作者 | Michael B. Jones John Bradley Nat Sakimura |
| 基礎標準 | JSON JSON Web Signature(JWS) JSON Web Encryption(JWE) |
| 領域 | 數據交換 |
| 縮寫 | JWT |
| 網站 | RFC 7519 |
JSON Web Token(JWT,建議讀音 /dʒɒt/,與英語單詞「jot」同音)[1]是一項擬議中的互聯網標準,用於建立帶有可選簽名和/或可選加密的數據,其有效載荷中保存用於斷言若干聲明的 JSON。這些令牌可以使用共享秘密,或使用公鑰/私鑰進行簽名。
例如,伺服器可以生成一個帶有「已作為管理員登錄」這一聲明的令牌,並將其提供給客戶端。客戶端隨後便可使用該令牌來證明自己已以管理員身份登錄。令牌可以由某一方的私鑰(通常是伺服器的私鑰)簽名,以便任何一方隨後都能驗證令牌是否合法。若另一方通過適當且可信的方式持有對應的公鑰,則其也能夠驗證該令牌的合法性。這些會話令牌被設計為緊湊、[2]URL安全、[3]且易於使用,尤其適用於網頁瀏覽器中的單點登錄(SSO)場景。JWT 聲明通常可用於在身份提供者與服務提供者之間傳遞已認證用戶的身份信息,或按業務流程需要傳遞其他類型的聲明。[4][5]
JWT 依賴其他基於 JSON 的標準:JSON Web Signature 與 JSON Web Encryption。[1][6][7]
結構
[編輯]- 標頭
- 用於標識生成簽名時所使用的算法。在下面的例子中,
HS256表示此令牌使用 HMAC-SHA256 進行簽名。
- 常見的密碼學算法包括使用 SHA-256 的 HMAC(HS256),以及使用 SHA-256 的 RSA 數字簽名(RS256)。JWA(JSON Web Algorithms)RFC 7518 還為認證與加密引入了更多算法。[8]
{ "alg": "HS256", "typ": "JWT" }
- 有效載荷
- 包含一組聲明。JWT 規範定義了七個已註冊聲明名稱,它們是通常包含在令牌中的標準字段。[1]此外,也常會根據令牌用途加入自定義聲明。
- 以下示例包含標準的簽發時間聲明(
iat)以及一個自定義聲明(loggedInAs)。 { "loggedInAs": "admin", "iat": 1422779638 }
- 簽名
- 用於安全地驗證令牌。簽名的計算方式是先將標頭與有效載荷分別使用 Base64url 編碼 RFC 4648,再以句點將二者連接成字符串。隨後,將該字符串輸入標頭中指定的密碼學算法中。本例使用帶有共享秘密的 HMAC-SHA256(也定義了公鑰算法)。Base64url 編碼與 Base64 類似,但使用不同的非字母數字字符,並省略填充字符。
HMAC_SHA256( secret, base64urlEncoding(header) + '.' + base64urlEncoding(payload) )
以上三部分分別使用 Base64url 編碼 RFC 4648 編碼,再以句點連接,構成 JWT:
const token: string = base64urlEncoding(header) + '.' + base64urlEncoding(payload) + '.' + base64urlEncoding(signature)
以上數據配合秘密「secretkey」會生成如下令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN
_oWnFSRgCzcmJmMjLiuyu5CSpyHI
(上述 JSON 字符串會被格式化為不帶換行與空格的 UTF-8 字節數組。這一點很重要,因為哪怕數據僅有細微變化,都會影響最終生成的令牌。)
由此生成的令牌可以方便地嵌入到 HTML 與 HTTP 中。[3]
用途
[編輯]在認證場景中,當用戶成功登錄後,通常會返回一個 JSON Web Token(JWT)。該令牌應通過安全機制發送給客戶端,例如使用HTTP-only Cookie。通常不建議將 JWT 存儲於瀏覽器的本地存儲機制中,例如 localStorage 或 sessionStorage。這是因為運行在客戶端的 JavaScript(包括瀏覽器擴展)可以訪問這些存儲機制,從而暴露 JWT 並危及安全性。若要在需要與跨來源 API 進行認證時使用 HTTP-only Cookie,較佳做法是使用 credentials 屬性,告知瀏覽器在 Fetch 調用時自動將 Cookie 發送至外部 API,例如:
fetch('https://api.example.com/data', {
method: 'GET',
credentials: 'include' // 告知浏览器一并发送 Cookie 等凭证
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
使用這種方式時,JWT 不會暴露給客戶端側 JavaScript;這是在遵循安全最佳實踐的同時使用 JWT 的較佳方式。對於無人值守的進程,客戶端也可以直接使用預共享密鑰生成並簽署自己的 JWT,然後將其傳遞給兼容 OAuth 的服務,如下所示:
POST /oauth2/token
Content-type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=eyJhb...
若客戶端傳遞了有效的 JWT 斷言,伺服器將生成一個可用於調用應用程式的 access_token,並將其返回給客戶端:
{
"access_token": "eyJhb...",
"token_type": "Bearer",
"expires_in": 3600
}
當客戶端希望訪問受保護的路由或資源時,用戶代理通常會發送 JWT,一般是在 Authorization HTTP標頭中使用 Bearer 方案。該標頭內容可能如下所示:
Authorization: Bearer eyJhbGci...<snip>...yu5CSpyHI
這是一種無狀態認證機制,因為用戶狀態並不會保存在伺服器內存中。伺服器上的受保護路由會檢查 Authorization 標頭中的 JWT 是否有效;若存在且有效,用戶便可訪問受保護資源。由於 JWT 是自包含的,所需信息都已包含其中,因此可減少多次查詢數據庫的需要。
標準字段
[編輯]| 代碼 | 名稱 | 說明 |
|---|---|---|
| 標準聲明字段 | 互聯網草案定義了以下標準字段(「聲明」),可用於 JWT 聲明集合中。 | |
iss
|
簽發者 | 標識簽發 JWT 的主體,例如組織名稱或網站 URL。 |
sub
|
主題 | 標識 JWT 的主題,例如用戶名或賬號編號。 |
aud
|
受眾 | 標識 JWT 的預期接收方。每個預期會處理該 JWT 的主體都必須在受眾聲明中以某個值標識自己。若處理該聲明的主體在存在 aud 聲明的情況下,無法以其中某個值標識自己,則該 JWT 必須被拒絕。
|
exp
|
過期時間 | 標識 JWT 在該時間及之後不得再被接受處理。其值必須為 NumericDate:[9] 即整數或小數,表示自 1970-01-01 00:00:00Z 起經過的秒數。 |
nbf
|
生效時間 | 標識 JWT 將從何時開始被接受處理。該值必須為 NumericDate。 |
iat
|
簽發時間 | 標識 JWT 被簽發的時間。該值必須為 NumericDate。 |
jti
|
JWT ID | 令牌的區分大小寫唯一標識符,即使在不同簽發者之間也應保持唯一。 |
| 常用標頭字段 | 以下字段常用於 JWT 的標頭中。 | |
typ
|
令牌類型 | 若存在,則必須設為一個已註冊的 IANA 媒體類型。 |
cty
|
內容類型 | 若使用嵌套簽名或嵌套加密,建議將其設為 JWT;否則應省略此字段。[1]
|
alg
|
算法 | 簽發者可以自由設置用於驗證令牌簽名的算法。然而,一些受支持算法並不安全。[10] |
kid
|
密鑰 ID | 提示客戶端使用了哪把密鑰來生成令牌簽名。伺服器會將此值與已存檔密鑰匹配,以驗證簽名有效且令牌真實。 |
x5c
|
X.509 證書鏈 | 一個 RFC4945 格式的證書鏈,對應於生成令牌簽名時所用的私鑰。伺服器將使用此信息驗證簽名有效且令牌真實。 |
x5u
|
X.509 證書鏈 URL | 一個 URL,伺服器可從中獲取與生成令牌簽名所用私鑰對應的證書鏈。伺服器將取得並使用這些信息驗證簽名真實。 |
crit
|
關鍵 | 一組伺服器必須理解的標頭列表,只有在理解這些標頭後,才可接受該令牌為有效。 |
| 代碼 | 名稱 | 說明 |
當前已註冊聲明名稱的列表可由 IANA 的 JSON Web Token Claims Registry 獲取。[11]
實現
[編輯]JWT 已有許多語言與框架的實現,包括但不限於:
漏洞
[編輯]JSON Web Token 可包含會話狀態。但如果項目需求允許在 JWT 到期前使會話失效,那麼服務就不能再僅憑令牌本身信任其中的斷言。若要驗證令牌中記錄的會話未被撤銷,則必須將令牌斷言與數據存儲進行比對。這樣一來,令牌就不再是無狀態的,從而削弱了 JWT 的主要優勢。[17]
安全顧問 Tim McLean 曾報告,某些 JWT 函式庫在使用 alg 字段驗證令牌時存在漏洞,最常見的情況是接受了 alg=none 的令牌。儘管這些漏洞後來已被修補,McLean 仍建議徹底棄用 alg 字段,以防止類似的實現混淆。[10]儘管如此,現實中仍不斷發現新的 alg=none 漏洞;在 2018 至 2021 年間,已有四個CVE與此原因有關。[18]
若設計得當,開發者可以通過採取以下預防措施來應對算法漏洞:[19][20]
- 不要僅憑 JWT 標頭驅動驗證流程
- 了解相關算法(避免只依賴
alg字段) - 使用適當大小的密鑰
2017 年,一些 JWT 函式庫被發現容易受到無效橢圓曲線攻擊。[21]
也有人認為,由於標準中提供了大量不同的加密算法與選項,JSON Web Token 難以被安全地使用,因此網頁前端[22]與後端[23]都應改用其他替代標準。
參見
[編輯]參考文獻
[編輯]- ^ 1.0 1.1 1.2 1.3 Jones, Michael B.; Bradley, John; Sakimura, Nat. JSON Web Token (JWT). IETF. 2015年5月. . RFC 7519. (美式英語).
- ^ Nickel, Jochen. Mastering Identity and Access Management with Microsoft Azure. Packt Publishing. 2016: 84 [2018-07-20]. ISBN 9781785887888.
- ^ 3.0 3.1 JWT.IO - JSON Web Tokens Introduction. jwt.io. [2018-07-20]. (原始內容存檔於2019-01-20).
- ^ Sevilleja, Chris. The Anatomy of a JSON Web Token. [2015-05-08]. (原始內容存檔於2021-11-09).
- ^ Atlassian Connect Documentation. developer.atlassian.com. [2015-05-08]. (原始內容存檔於2015-05-18).
- ^ Jones, Michael B.; Bradley, John; Sakimura, Nat. draft-ietf-jose-json-web-signature-41 - JSON Web Signature (JWS). tools.ietf.org. 2015年5月 [2015-05-08].
- ^ Jones, Michael B.; Hildebrand, Joe. draft-ietf-jose-json-web-encryption-40 - JSON Web Encryption (JWE). tools.ietf.org. 2015年5月 [2015-05-08].
- ^ Jones, Michael B. draft-ietf-jose-json-web-algorithms-40 - JSON Web Algorithms (JWA). tools.ietf.org. 2015年5月 [2015-05-08].
- ^ Jones, Michael B.; Bradley, Bradley; Sakimura, Sakimura. "exp" (Expiration Time) Claim. JSON Web Token (JWT). IETF. 2015年5月: sec. 4.1.4. . RFC 7519. .
- ^ 10.0 10.1 McLean, Tim. Critical vulnerabilities in JSON Web Token libraries. Auth0. 2015-03-31 [2016-03-29].
- ^ JSON Web Token (JWT). IANA. 2015-01-23 [2024-12-05] (美國英語).
- ^ POCO C++ Libraries 函式庫中的
Poco::JWT - ^ jose: JSON Object Signing and Encryption (JOSE) and JSON Web Token (JWT) library. Hackage. [2022-12-25].
- ^ jsonwebtoken. npm. [2018-05-07].
- ^ Crypt::JWT 於 CPAN
- ^ net-jwt 於 pkgs.racket-lang.org
- ^ Slootweg, Sven. Stop using JWT for sessions. joepie91 Ramblings. [2018-08-01].
- ^ CVE - Search Results. cve.mitre.org.
- ^ Common JWT security vulnerabilities and how to avoid them. [2018-05-14] (英語).
- ^ Andreas, Happe. JWT: Signature vs MAC attacks. snikt.net. [2019-05-27].
- ^ Critical Vulnerability in JSON Web Encryption. Auth0 - Blog. [2023-10-14] (英語).
- ^ No Way, JOSE! Javascript Object Signing and Encryption is a Bad Standard That Everyone Should Avoid - Paragon Initiative Enterprises Blog. paragonie.com. [2023-10-13].
- ^ Pitfalls of JWT Authorization. authzed.com. [2023-11-16].
