如果你是網頁開發者,你一定聽過 JWT(JSON Web Token)。它幾乎出現在每個現代 Web 應用的身份驗證系統中。但 JWT 到底是什麼?為什麼要用它?什麼時候不該用它?
這篇文章會讓你徹底搞懂 JWT,從原理到實作,從優點到陷阱。
JWT 是什麼?
JWT 是一種開放標準(RFC 7519),用來在各方之間安全地傳遞 JSON 格式的資訊。這個資訊經過數位簽章,可以被驗證和信任。
一個 JWT 看起來像這樣:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4iLCJpYXQiOjE1MTYyMzkwMjJ9.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c看起來像亂碼?其實它由三個部分組成,用點(.)分隔:
1. Header(標頭)
{
"alg": "HS256",
"typ": "JWT"
}告訴系統這是一個 JWT,以及使用什麼演算法簽章。
2. Payload(載荷)
{
"sub": "1234567890",
"name": "John",
"iat": 1516239022
}實際要傳遞的資料。可以包含使用者 ID、角色、過期時間等。
3. Signature(簽章)
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)用來驗證 token 沒有被竄改。
為什麼需要 JWT?
在傳統的 Session 認證中:
- 用戶登入,伺服器建立 Session,存在記憶體或資料庫
- 伺服器回傳 Session ID(通常存在 Cookie)
- 每次請求,瀏覽器自動送出 Cookie
- 伺服器查詢 Session 確認身份
這個方法的問題:
- 擴展性差:多台伺服器需要共享 Session 狀態
- 效能開銷:每次請求都要查資料庫
- 跨域困難:Cookie 有 Same-Origin 限制
JWT 如何解決這些問題
JWT 是無狀態(Stateless)的:
- 用戶登入,伺服器生成 JWT,不需要儲存
- 把 JWT 回傳給客戶端
- 客戶端每次請求帶上 JWT(通常在 Header)
- 伺服器只需要驗證簽章,不需要查資料庫
這帶來巨大的優勢:
- ✅ 水平擴展:任何伺服器都能驗證,不需要共享狀態
- ✅ 效能優秀:不需要查資料庫
- ✅ 跨域友好:可以輕鬆用於 API、微服務
- ✅ 行動裝置友好:不依賴 Cookie
JWT 的實際應用
典型的登入流程
1. POST /login {email, password}
2. 伺服器驗證身份
3. 伺服器生成 JWT,包含 {userId, role, exp}
4. 回傳 JWT 給客戶端
5. 客戶端儲存 JWT(localStorage 或 httpOnly Cookie)
6. 之後的請求:Authorization: Bearer {jwt}
7. 伺服器驗證 JWT 簽章,提取用戶資訊JWT 裡面應該放什麼?
應該放的:
- 用戶 ID
- 用戶角色/權限
- token 過期時間(exp)
- token 簽發時間(iat)
不應該放的:
- ❌ 密碼
- ❌ 完整的個人資料
- ❌ 敏感資訊
為什麼?因為 JWT 的 Payload 只是 Base64 編碼,任何人都能解碼看到內容。簽章只保證「沒被竄改」,不保證「加密」。
JWT 的安全陷阱
1. 別用 "alg": "none"
JWT 標準允許不簽章(alg: none),這是一個巨大的安全漏洞。務必在伺服器端檢查並拒絕 none 演算法。
2. 使用強密鑰
如果使用 HS256(對稱加密),密鑰必須夠長夠隨機:
// ❌ 錯誤
const secret = "password123";
// ✅ 正確
const secret = "a3f8b2c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1";3. 設定合理的過期時間
- Access Token:15 分鐘 ~ 1 小時
- Refresh Token:7 天 ~ 30 天
越短越安全,但使用者體驗越差。需要平衡。
4. Token 無法被撤銷
這是 JWT 最大的問題:一旦簽發,在過期之前都有效。
解決方案:
- 短過期時間 + Refresh Token
- 維護黑名單(但這又引入了狀態)
- Token 版本號(登出時遞增版本號)
5. 儲存位置的選擇
| 儲存方式 | XSS 風險 | CSRF 風險 |
|---|---|---|
| localStorage | ❌ 高 | ✅ 無 |
| 普通 Cookie | ❌ 高 | ❌ 高 |
| httpOnly Cookie | ✅ 低 | ⚠️ 中 |
最佳實踐:使用 httpOnly + Secure + SameSite Cookie。
Access Token + Refresh Token 模式
為了平衡安全性和使用體驗,現代應用通常使用雙 Token 模式:
Access Token
- 短期有效(15 分鐘)
- 用於 API 請求
- 存在記憶體或 localStorage
Refresh Token
- 長期有效(7-30 天)
- 只用來換取新的 Access Token
- 存在 httpOnly Cookie
- 可以被撤銷(存在資料庫)
流程
1. 登入 → 取得 Access Token + Refresh Token
2. API 請求 → 使用 Access Token
3. Access Token 過期 → 用 Refresh Token 換新的
4. Refresh Token 過期 → 重新登入
5. 登出 → 撤銷 Refresh Token什麼時候不該用 JWT?
JWT 不是銀彈,有些情況下 Session 反而更適合:
- 需要即時撤銷:例如用戶被封鎖後要立即失效
- 單一伺服器:Session 的複雜度更低
- 敏感操作:銀行轉帳等場景,可能需要更嚴格的驗證
實作範例(Node.js)
const jwt = require("jsonwebtoken");
// 生成 Token
const token = jwt.sign(
{ userId: 123, role: "admin" },
process.env.JWT_SECRET,
{ expiresIn: "15m" }
);
// 驗證 Token
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log(decoded.userId); // 123
} catch (err) {
console.log("Token 無效或過期");
}總結
JWT 是現代 Web 開發的重要工具,但使用時要注意:
- ✅ 理解 JWT 是「簽章」不是「加密」
- ✅ 使用強密鑰
- ✅ 設定合理的過期時間
- ✅ 考慮使用 Refresh Token 模式
- ✅ 正確選擇儲存位置
- ❌ 不要在 Payload 放敏感資訊
- ❌ 不要接受 alg: none
掌握這些原則,你就能安全地使用 JWT 建立現代化的身份驗證系統。