JWT Stateless Design at Scale with Forced Logout Gaps¶
概念概覽
設計意圖(非漏洞)¶
核心知識¶
設計意圖(非漏洞)¶
ValidateToken 不查帳號狀態是刻意設計,原因:1M CCU / 500K RPS 下,每個請求查 DB 或 Redis 在技術上不可行。stateless 驗證只驗 JWT 簽名與 TTL(1h),這是效能與安全的刻意 tradeoff,不是遺漏。
前端持有有效 refresh token 期間,即使 device record 刪除或 Redis refresh token 撤銷,access JWT(1h TTL)仍然有效 — 這是設計行為,最多有 1h 的 revoke 延遲視窗。
現有強制登出缺口清單¶
| 缺口 | 現況 | 影響 |
|---|---|---|
| Admin RPC 入口 | RevokeAccountTokens() 存在但無 gRPC endpoint 暴露 |
Ban 操作無法立即撤銷 token |
| Ban hook | player.ban 狀態變更時未自動呼叫 RevokeAccountTokens() |
Ban 後玩家仍可用舊 token 繼續遊戲 |
| Force logout push | gRPC Stream / Redis Pub/Sub 機制未實作 | Game Server 無法主動關閉 WebSocket |
Phase 3 補齊路徑¶
1. ForceLogoutAccount admin gRPC RPC → 暴露 RevokeAccountTokens()
2. player.ban 狀態變更 hook → 自動呼叫 RevokeAccountTokens()
3. Redis Pub/Sub → Game Server 訂閱 → 主動關閉 WebSocket
即使實作上述機制,access JWT 的 1h TTL 窗口無法完全消除,除非改為 stateful(在 500K RPS 下不可行)。
經驗教訓¶
-
stateless JWT 的 revoke 延遲是效能設計的必然代價,不應誤判為安全漏洞
-
RevokeAccountTokens() 存在但沒有暴露入口,是典型的「功能實作了但無法被觸發」的架構缺口
-
強制登出需要三個環節同時到位:撤銷 token、關閉現有連線、阻止 refresh — 缺任何一環都不完整
常見陷阱¶
-
把 stateless JWT 不查帳號狀態誤判為 P0 安全漏洞,浪費 sprint 資源
-
只實作 RevokeAccountTokens() 但不加 ban hook → ban 操作需要手動呼叫 RPC,容易被遺漏
-
只撤銷 refresh token 但不關閉 WebSocket → 玩家仍在線上繼續遊戲直到斷線重連
相關概念¶
相關視角¶
以下頁面與本概念共享主題,但從不同角度切入。保留獨立視角同時提供交叉參考:
- Hero Unlock Idempotency — 共享:
1m-ccu,game-backend/ 獨特:distributed-system,hero-unlock
來源 Sessions¶
| 日期 | Session | 貢獻摘要 |
|---|---|---|
| 2026-04-02 | d088842d-abec-48fc-8a1a-779a5f74e05d | 釐清高 CCU 環境下 stateless JWT 的設計意圖,並系統性列出強制登出機制的現有缺口與 Phase 3 補齊清單 |