這篇文章記錄一次 JWT 雙票(AT/RT)治理的實際經驗。
我們想回答的問題很簡單:當刷新令牌在異常情境下被重放時,系統能不能快速發現並收口。
說明:本文的網域、IP、帳號識別、會話識別與日誌內容皆為脫敏示例,不對應任何真實生產資料。
系統邊界如下:
- 前端:Web SPA(AT 僅存於記憶體)
- 後端:Go + Gin(鑑權與刷新)
- 會話層:Redis(令牌狀態索引)
- 閘道:HTTPS 反向代理
現象與觸發條件
在儲能雲平台的日常安全演練中,我們針對大量邊緣閘道與前端看板流量做了認證鏈路滲透測試,其中包含「舊 RT 被攔截後重複提交」的極端情境。
舊方案雖然有 AT/RT 分層,但刷新路徑缺少完整狀態約束,舊 RT 在短時間並發下仍可能被利用。
脫敏事件樣式如下:
{
"event": "auth.refresh.reuse_detected",
"user_id_masked": "u-***39",
"session_id": "s-***b1",
"ip_masked": "10.**.**.21",
"action": "session_revoked"
}
排查與改造策略:保留 AT 無狀態,強化 RT 治理
我們沒有改動雙票結構,而是針對 RT 刷新主路徑補齊治理能力,目標是可撤銷、可審計、可回收。
第一層:維持清楚的令牌分工
- AT 負責高頻請求,走
Authorization: Bearer - RT 僅透過 HttpOnly Cookie 傳輸
- AT 校驗維持無狀態,確保效能與擴展性
這樣可以把控制面集中在 RT,不影響 AT 的輕量存取。
第二層:把 RT 刷新收斂為單次可追蹤流程
刷新路徑遵循固定順序:校驗舊 RT -> 簽發新 RT -> 更新 Redis 狀態 -> 失效舊 RT。
Redis Key 模型(脫敏示例):
rt:active:{jti} -> { user_id, session_id, exp } // 核心狀態,TTL 跟隨 RT 到期
rt:session:{session_id} -> Set<jti> // 冗餘索引,用於會話級一鍵清理
rt:deny:{jti} -> 1 (TTL=剩餘有效期) // 黑名單,攔截被重放的舊票據
user:sessions:{user_id} -> Set<session_id> // 使用者級管控,支援「踢出其他裝置」
對應約束:
- 同一 RT 僅允許成功刷新一次
- 新 RT 生效後,舊 RT 立即進入 deny 清單
- 刷新流程加入短時鎖,避免並發競態
並發防抖設計(結果復用視窗)
現代 SPA 常會同時送出多個請求,若沒有防抖協調,舊 RT 可能在同一時間觸發多次刷新,進而讓合法請求被誤判為重放。為此我們設計了 5 秒復用視窗:
- 第一個請求先拿鎖並完成 RT 輪換
- 輪換後的 AT/RT 會快取 5 秒
- 同 key 的併發請求在 5 秒內直接復用同一組 AT/RT,不再二次輪換
- 視窗到期後,恢復嚴格單次輪換策略
第三層:重放事件的處置方式
一旦識別 RT 重放,系統會對相關會話執行失效、寫入審計事件,並引導前端回到登入流程。
重點不是硬撐原會話,而是盡快終止風險會話。
第四層:讓登出與高風險操作觸發服務端吊銷
以下操作統一接入會話失效流程:
- 使用者主動登出
- 管理員重設密碼
- 使用者狀態切換為鎖定或停用
也就是說,登出不再只是刪除瀏覽器 Cookie,而是服務端狀態同步失效。
根因總結
這次問題本質上是治理深度不足,而非單一程式錯誤:
- 早期實作以簽發與驗簽為主,對令牌生命週期覆蓋不足。
- 會話狀態能力雖已預留,但未完整接入刷新主鏈路。
改造後的收益
這次治理後,鏈路上的變化主要有三點:
- 會話可在服務端快速撤銷
- RT 重放可被識別並追蹤
- 安全事件可按使用者與會話維度快速定位
對使用者體驗影響可控:正常路徑維持無感刷新,異常路徑回到重新登入。
過程改進與行動項
1)把令牌生命週期校驗納入發版檢查
發版前固定校驗:
- RT 單次使用驗證
- 刷新並發一致性驗證
- 登出/重設密碼後的會話失效驗證
2)統一安全審計欄位
審計日誌統一採用脫敏欄位:user_id_masked、session_id、jti_prefix、ip_masked、ua_hash、risk_level。
3)固定進行重放演練
每月執行一次 RT 重放演練,持續驗證告警、失效與回收流程是否正常。
Phase 2 演進路線(Roadmap):從會話可控到上下文零信任
經過這次改造,Phase 1 已完成核心目標:建立 Redis 會話撤銷鏈路與並發防重放機制。Refresh 流程已能即時校驗使用者狀態,帳號一旦鎖定或停用,會立即阻斷新票據簽發。
下一階段將針對高階 Token 劫持場景持續演進:
- 上下文感知風控:規劃引入環境指紋(IP 段 + UA Hash)比對。當 RT 出現異常地域跳變時,自動執行 AT/RT 全量失效,並聯動帳號凍結與第三方二次身分驗證。
- 誤判治理:考量工業現場常見的 4G/5G 頻繁切網與出口漂移,相關策略會先完成風控模型調優,再以灰度方式逐步切入主鏈路。
結語
認證安全真正的考驗,不在簽發速度,而在異常發生後的收口速度。
這次改造最有價值的地方,是讓 AT/RT 架構從「可用」進一步走向「可治理」。