一次 JWT 稽核背後的七個盲點
朋友的 JWT 認證跑得動,簽章也驗過了,但七個安全缺口全開著。這七篇筆記是那次稽核的產物。
「JWT 簽了章不代表安全。簽章只回答一個問題:有沒有被改過。」
情境
朋友用 vibe coding 做了一個多人連線的 side project。JWT 認證跑得動。用戶能登入,能打 API。我幫他看 code 的時候,發現 jwt.verify 沒有 pin 演算法。
我跟他說這裡有問題。他一臉困惑:「簽章驗過不就好了嗎?」
他的反應讓我意識到,我自己也只是隱約知道不對,但說不清楚為什麼。於是我從頭研究了一遍,把整套 JWT 安全模型搞懂,再回來跟他解釋。拉開一看,七個缺口全開著:
- 沒有 pin 演算法,攻擊者能偽造簽章
- 沒有
iss,別的服務簽的 token 也能通過 - 沒有
aud,refresh token 能當 access token 用 - 沒有
exp搭配輪替,偷到的 token 永遠有效 - 沒有 timing-safe 比對,旁道攻擊能逐字猜密鑰
我花了一週從頭補齊。這七篇筆記是那次稽核的產物。
七塊拼圖
1. JWT 是什麼
Token 有三段:header、payload、signature。前兩段任何人都能讀。簽章是唯一需要金鑰的部分。JWT 不是加密。
深入閱讀:JWT 是什麼
2. 對稱與非對稱簽章
HS256 用一把共享密鑰。RS256 用兩把,私鑰簽,公鑰驗。選哪個取決於一個問題:驗證方能不能擁有簽章能力?
深入閱讀:對稱與非對稱簽章
3. 六個標準宣告
簽章只擋竄改。六個 claim 各自擋住一條不同的攻擊路徑。跳過任何一個,對應的缺口就打開。
深入閱讀:六個標準宣告
4. iss 宣告
iss 標記誰簽了 token。沒有它,任何拿到同一把密鑰的服務都能簽出合法 token。
深入閱讀:iss 宣告
5. 演算法混淆與 none 攻擊
JWT header 的 alg 欄位由客戶端控制。攻擊者能改成 none 或混淆簽章類型。Server 端 pin 演算法就能堵住。
深入閱讀:演算法混淆與 none 攻擊
6. 存取與刷新令牌輪替
一個 token 逼你在安全和體驗之間二選一。兩個 token 解決這個取捨。搭配 reuse detection,攻擊窗口縮到 15 分鐘。
深入閱讀:存取與刷新令牌輪替
7. 時間安全比對
嚴格等號在第一個不匹配字元就停下。回應時間洩漏了正確字元數。timingSafeEqual 走完整個長度,時間固定。
深入閱讀:時間安全比對
帶走一句
「簽章是第一步,不是終點。六個宣告加上 timing-safe 比對,才是真正的防線。」
參考來源
- RFC 7519, JSON Web Token
- RFC 7518, JSON Web Algorithms
- Curity JWT Best Practices
- PortSwigger Algorithm Confusion
- Descope Refresh Token Rotation
Related
JWT 是什麼 · 對稱與非對稱簽章 · 六個標準宣告 · iss 宣告 · 演算法混淆與 none 攻擊 · 存取與刷新令牌輪替 · 時間安全比對