Engineering · 3 min read
存取與刷新令牌輪替
一個 token 逼你在安全和體驗之間二選一。兩個 token 搭配輪替和 reuse detection,攻擊窗口縮到 15 分鐘。
一個 token 逼你做取捨:短 TTL(安全,但體驗差)或長 TTL(體驗好,但攻擊窗口大)。兩個 token 解決這個問題。
| Access | Refresh | |
|---|---|---|
| TTL | 5-15 分鐘 | 1-7 天 |
| 送往 | 每個 API endpoint | 只有 /refresh |
| 儲存位置 | 記憶體(JS 變數) | httpOnly cookie |
| JS 能讀? | 是(Authorization header) | 否(擋住 XSS) |
aud | my-app | my-refresh |
每個 refresh token 帶一個唯一的 jti。Server 追蹤它的狀態:active 或 used。/refresh 發行新的一對後,舊 token 變成 used。再次使用 used 的 token 會觸發 reuse detection,server 撤銷整個 token 家族。15 分鐘的 access TTL 限制了攻擊窗口。真正用戶的 token 過期後,/refresh 呼叫就會抓到竊取。
Cookie 旗標(httpOnly 是 cookie 旗標,不是協定):
HttpOnly:對 JavaScript 隱藏 cookie。Secure:只透過 HTTPS 送出 cookie。SameSite=Strict:阻擋跨站請求攜帶 cookie。
稽核中的發現: auth-service 簽 access token 用
aud: 'my-app',refresh token 用aud: 'my-refresh'。輪替時從 DB 重新取最新的 email 和 displayName。
「一個 token 是取捨。兩個 token 是解法。」
參考來源
Related
回到總覽:一次 JWT 稽核背後的七個盲點 · 六個標準宣告 · iss 宣告 · 演算法混淆與 none 攻擊