JWT
Tech ·JWT
1. 什麼是 JWT?
JSON Web Token (JWT) 是一種開放標準(RFC 7519),定義了一種簡潔(compact)且自包含(self-contained)的方式,用於在各方之間安全地傳遞資訊作為 JSON 物件。JWT 透過數位簽章確保資料的完整性和真實性,可以使用對稱金鑰(HMAC)或非對稱金鑰(RSA、ECDSA)進行簽名。
關鍵特性
-
簡潔(Compact):體積小,可在 URL、POST 參數或 HTTP Header 中發送,傳輸速度快
-
自包含(Self-contained):payload 包含所需資訊,無需重新查詢資料庫
-
跨平台支援:基於 JSON 格式,大部分程式語言都支援
2. JWT 的結構
JWT 由三個部分組成,使用點(.)分隔:
HEADER.PAYLOAD.SIGNATURE
2.1 Header(標頭)
Header 描述 JWT 的元資訊,通常包含:
{
"alg": "HS256", // 簽名演算法
"typ": "JWT" // Token 類型
}
主要欄位:
-
alg:簽名演算法,對於未加密的 JWT 設為 none
-
typ:媒體類型,通常設為 JWT
-
cty:內容類型,用於嵌套 JWT(很少使用)
2.2 Payload(負載)
Payload 包含聲明(Claims),分為三類:
註冊聲明(Registered Claims):
- iss(issuer):發行者
- sub(subject):主體,通常為使用者 ID
- aud(audience):受眾,預期接收方
- exp(expiration time):過期時間(UNIX 時間戳)
- nbf(not before):生效時間
- iat(issued at):簽發時間
- jti(JWT ID):唯一識別符,防止重放攻擊
公開聲明(Public Claims):在 IANA 註冊或使用防衝突名稱
私有聲明(Private Claims):自定義的應用程式特定資訊
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"iat": 1516239022
}
2.3 Signature(簽名) Signature 用於驗證 JWT 的完整性和真實性:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
3. JWT 的運作流程
-
使用者登入:提供身份驗證資訊
-
伺服器驗證:驗證使用者身份
-
簽發 JWT:伺服器生成並回傳 JWT
-
攜帶 Token:客戶端在後續請求中攜帶 JWT
-
驗證授權:伺服器驗證 JWT 的有效性並授權存取
Authorization: Bearer <token>
這種方式實現了無狀態認證(Stateless Authentication),伺服器無需儲存 session 資訊。
4. 使用場景
4.1 授權(Authorization)
-
API 認證與微服務架構
-
使用者權限驗證
-
跨域資源存取
4.2 單點登入(SSO)
-
跨網域身份驗證
-
多應用程式間的無縫存取
-
企業級身份管理
4.3 資訊交換
-
安全的資料傳輸
-
微服務間的通訊
-
第三方 API 整合
5. 簽名演算法
5.1 HMAC 演算法
-
HS256:HMAC + SHA-256(必須支援)
-
HS384:HMAC + SHA-384
-
HS512:HMAC + SHA-512
特點:使用共享密鑰,任何擁有密鑰的一方都可以驗證和生成簽名。
5.2 RSA 演算法
-
RS256:RSA + SHA-256(推薦)
-
RS384:RSA + SHA-384
-
RS512:RSA + SHA-512
特點:使用非對稱密鑰,私鑰簽名,公鑰驗證,實現一對多的安全分發。
5.3 ECDSA 演算法
-
ES256:ECDSA + P-256 + SHA-256(推薦)
-
ES384:ECDSA + P-384 + SHA-384
-
ES512:ECDSA + P-521 + SHA-512
6. 安全考量
6.1 儲存安全
-
避免使用 localStorage/sessionStorage:建議使用 HTTP-only Cookie
-
保護密鑰:妥善管理簽名密鑰,防止洩漏
6.2 演算法安全
-
強制指定演算法:不要依賴 alg 欄位,在伺服器端明確指定可接受的演算法
-
防止 none 演算法攻擊:拒絕接受 alg: none 的未簽名 JWT
6.3 資料敏感性
-
避免存放敏感資訊:JWT 的 payload 可以被輕易解碼,不要存放密碼、身份證號等敏感資料
-
控制 payload 大小:避免超過 HTTP header 限制(通常 8KB)
6.4 生命週期管理
-
設定適當的過期時間:使用 exp 聲明控制 token 有效期
-
無法撤銷問題:JWT 在有效期內無法單獨撤銷,需要考慮黑名單機制或縮短有效期
7. 優點與缺點
7.1 優點
-
無狀態:減少伺服器端資源負擔
-
跨域支援:適合分散式架構
-
標準化:基於開放標準,互操作性好
-
自包含:減少資料庫查詢次數
-
可擴展:支援自定義聲明
7.2 缺點
-
無法撤銷:一旦簽發就無法撤銷
-
大小限制:可能超過 URL 或 Cookie 限制
-
密鑰管理:需要妥善管理簽名密鑰
-
安全風險:容易受到 XSS 攻擊
8. 實作範例
8.1 Node.js 範例
const jwt = require('jsonwebtoken');
const secret = 'your-256-bit-secret';
// 簽發 JWT
const payload = {
sub: '1234567890',
name: 'John Doe',
iat: Math.floor(Date.now() / 1000)
};
const token = jwt.sign(payload, secret, {
algorithm: 'HS256',
expiresIn: '1h'
});
// 驗證 JWT
try {
const decoded = jwt.verify(token, secret, {
algorithms: ['HS256']
});
console.log('Decoded payload:', decoded);
} catch (err) {
console.error('Invalid token:', err.message);
}
8.2 Ruby 範例
require 'json'
require 'base64'
require 'openssl'
# 建立 header 和 payload
header = { alg: "HS256", typ: "JWT" }
payload = { sub: "1234567890", name: "John Doe", admin: true }
# Base64 編碼
encoded_header = Base64.urlsafe_encode64(JSON(header))
encoded_payload = Base64.urlsafe_encode64(JSON(payload))
# 生成簽名
digest = OpenSSL::Digest::SHA256.new
data = "#{encoded_header}.#{encoded_payload}"
signature = OpenSSL::HMAC.digest(digest, 'secret', data)
encoded_signature = Base64.urlsafe_encode64(signature).gsub('=', '')
# 完整的 JWT
jwt_token = "#{encoded_header}.#{encoded_payload}.#{encoded_signature}"
puts jwt_token
9. JWT 的擴展規範
9.1 JSON Web Signature (JWS)
-
定義於 RFC 7515
-
提供數位簽名功能
-
確保資料完整性和來源真實性
9.2 JSON Web Encryption (JWE)
-
定義於 RFC 7516
-
提供加密功能
-
確保資料機密性
9.3 JSON Web Key (JWK)
-
定義於 RFC 7517
-
統一密鑰表示格式
-
簡化密鑰管理和共享
10. 最佳實踐
10.1 設計原則
-
最小權限原則:只在 payload 中包含必要的資訊
-
短生命週期:設定較短的過期時間
-
強簽名演算法:使用 RS256 或 ES256 而非 HS256
10.2 實作建議
-
使用 HTTPS:確保傳輸過程中的安全性
-
定期輪換密鑰:降低密鑰洩漏的風險
-
實作刷新機制:透過 refresh token 延長使用期限
10.3 監控與日誌
-
記錄異常:監控無效 token 的使用
-
審計追蹤:記錄 token 的簽發和使用歷史
11. 總結
JWT 是一種強大且靈活的身份驗證和授權機制,特別適合現代的分散式系統架構。雖然存在一些安全考量,但透過適當的實作和安全措施,JWT 能夠提供安全、高效的身份驗證解決方案。
在選擇 JWT 時,需要根據具體的應用場景權衡其優缺點,並確保遵循最佳實踐以最大化安全性和效能。對於需要即時撤銷功能的應用,可能需要結合其他技術(如 Redis 黑名單)來補強 JWT 的限制。