你可能已經用過 JWT 來實作登入系統:
使用者登入後,系統簽發一組 Token,接下來每個 API 請求都帶著這個 Token,就能驗證身份。
聽起來簡單又有效,但如果你沒設好:
-
Token 可能被竊取
-
使用者權限可能被偽造
-
系統可能毫無防備地被入侵
JWT 的確方便,但它不是萬能,實作不當反而變成系統最大的漏洞。
這篇文章帶你從實作邏輯到攻防觀念,了解 JWT 的正確使用方式與常見錯誤。
一、JWT 是什麼?為什麼被廣泛使用?
JWT(JSON Web Token)是一種以 JSON 格式編碼、具有簽章機制的 Token。
常用於前後端分離架構的身份驗證。
結構:
header.payload.signature
-
Header:定義演算法與類型
-
Payload:包含用戶資料(如 userId, role)
-
Signature:用來驗證資料是否被竄改(以 secret 或私鑰簽名)
JWT 可由伺服器產生,客戶端保存(如 localStorage、cookie)並在每次請求中附上。
二、JWT 正確的產生與驗證流程(Node.js 範例)
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{ userId: 123, role: 'user' },
'mySecretKey',
{ expiresIn: '1h' }
);
const decoded = jwt.verify(token, 'mySecretKey');
三、最常見的 5 大安全誤區
1. 不設過期時間(exp)
錯誤:
jwt.sign(payload, secret); // 沒有 expiresIn
這樣產生的 token 永遠有效,被竊取後可永久使用。
正確:
jwt.sign(payload, secret, { expiresIn: '1h' });
2. 把敏感資料放進 payload
JWT 的內容是 base64 編碼,不是加密!任何人都能 decode。
// 不該放:
{ "password": "123456", "cardNumber": "****" }
建議: payload 只放必要的識別資訊(如 userId, role),敏感資料不要放進去。
3. 演算法被降級攻擊
攻擊者可自行產生:
{ "alg": "none" }
如果伺服器不驗證演算法,就可能讓未簽名的 token 被接受。
防禦方式:
-
永遠指定使用的演算法(如 HS256)
-
拒絕處理
alg: none的 token
4. Secret 選得太弱或公開
選擇太簡單的 secret(如 123456),或把 secret 寫在前端代碼中,將使所有 token 都可被偽造。
建議:
-
Secret 至少 32 字元以上,隨機產生
-
使用
.env管理環境變數,切勿硬編碼在程式碼中
5. 未驗證權限角色
JWT 中的 payload 可能有:
{ "userId": 1, "role": "admin" }
攻擊者若能偽造或重放舊 token,可能藉此取得不該有的權限。
建議:
-
每次 API 請求都要重新驗證該用戶是否真的具備對應角色權限
-
不要僅憑 token 裡的
role判斷權限
四、JWT 要儲存在哪裡才安全?
| 儲存位置 | 優點 | 缺點 |
|---|---|---|
| localStorage | 操作簡單 | 易受 XSS 攻擊 |
| cookie(httpOnly) | 可避免 XSS | 需防 CSRF |
| sessionStorage | 僅限同一分頁 | 關閉即失效 |
建議: 若能設計 CSRF 防禦機制,使用 httpOnly cookie 儲存 token 是較安全的選擇。
五、結語:JWT 是利器也是風險,安全實作才是關鍵
JWT 不是用來保存資料的容器,而是短期憑證。
只要實作正確,它能讓系統驗證機制簡潔高效;但若忽略細節,它也可能成為攻擊者入侵的後門。
安全性從來都不只是有沒有加密,而是你怎麼控制使用者的行為範圍與資料存取邏輯。
評論