JWT 安全漏洞
常見 JWT 攻擊
1. None 演算法攻擊
import jwt
# 攻擊者修改 header: {"alg": "none"}
token = "eyJhbGciOiAibm9uZSJ9.eyJ1c2VyX2lkIjogMX0."
# 某些舊版函式庫會接受 none 演算法!
# ✅ 安全寫法 - 指定演算法
jwt.decode(token, secret, algorithms=["HS256"])
2. 弱密鑰爆破
# 攻擊者嘗試常見密鑰
common_secrets = ["secret", "password", "123456", "key", "jwt_secret"]
for s in common_secrets:
try:
payload = jwt.decode(token, s, algorithms=["HS256"])
print(f"密鑰找到了: {s}")
break
except:
pass
3. Vibe Prompt
「幫我實作安全的 JWT 認證中間件:使用 RS256(非對稱加密)、設定短有效期、加入 Refresh Token 機制。」
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer
import jwt, time
app = FastAPI()
security = HTTPBearer()
PRIVATE_KEY = open("private.pem").read()
PUBLIC_KEY = open("public.pem").read()
def create_access_token(user_id: int):
return jwt.encode({
"user_id": user_id,
"exp": time.time() + 3600, # 1 小時
"iat": time.time()
}, PRIVATE_KEY, algorithm="RS256")
def verify_token(credentials=Depends(security)):
try:
payload = jwt.decode(
credentials.credentials, PUBLIC_KEY,
algorithms=["RS256"]
)
return payload["user_id"]
except jwt.ExpiredSignatureError:
raise HTTPException(401, "Token 已過期")
except jwt.InvalidTokenError:
raise HTTPException(401, "無效 Token")
@app.get("/me")
def get_me(user_id=Depends(verify_token)):
return {"user_id": user_id}
關鍵要點
- ✅ JWT = Header.Payload.Signature(三段式)
- ✅ 最常見攻擊:演算法混淆 (
alg: none)、弱密鑰、Token 洩漏 - ✅ 驗證 JWT 時必須:1) 驗證簽章 2) 檢查過期時間 3) 限制演算法白名單
- ✅ 對稱式 (HS256) vs 非對稱式 (RS256) 各有適用場景
JWT 攻擊檢測清單
| 測試項目 | 工具 |
|---------|------|
| alg: none 攻擊 | jwt_tool, Burp Suite |
| 弱 HMAC 密鑰爆破 | hashcat, John |
| RS256 公鑰取得 | /.well-known/jwks.json |
| Token 過期檢查 | 手動修改 exp 標籤 |
| Token 儲存安全 | 檢查 LocalStorage / Cookie |
import jwt
# ❌ 不安全:沒有指定演算法
payload = jwt.decode(token, options={"verify_signature": False})
# ✅ 安全:指定允許的演算法
payload = jwt.decode(token, public_key, algorithms=["RS256"])
常見錯誤
程式碼範例
JWT 安全:不只是簽章驗證
JWT(JSON Web Token)是現代 API 最主流的認證方式。但實作不當會導致嚴重的安全漏洞。
常見的 JWT 漏洞
| 漏洞 | 風險 | 測試方式 |
|:----|:----|:--------|
| 演算法混淆 | 伺服器接受 alg: none | 修改 JWT Header 為 "alg":"none" |
| 弱金鑰 | 金鑰太短或可被暴力破解 | 用 John the Ripper 破解 HS256 金鑰 |
| 金鑰洩漏 | 金鑰寫在程式碼或公開 repo | 搜尋 GitHub 上的 jwt_secret |
| 未驗證過期 | exp 過期的 token 仍可使用 | 使用已過期的 token 測試 |
| KID 注入 | kid 參數可被注入路徑遍歷 | 修改 kid 為 ../../etc/passwd |
JWT 安全實作檢查清單
- [ ] 使用 RS256(非對稱)而非 HS256(對稱)
- [ ] 驗證
alg參數,拒絕none - [ ] 驗證
exp、nbf、iss、aud欄位 - [ ] 金鑰長度至少 256 bits
- [ ] 金鑰定期輪換
下一章預告:SQL/NoSQL 注入
JWT 漏洞繞過的是認證。下一章的注入攻擊繞過的是資料庫——不需要合法 Token 也能讀取資料。