Dev Tools
回文章列表·8 min

JWT 深入解析:三段結構、HS256 vs RS256、常見漏洞與安全儲存

JWT(JSON Web Token)是過去十年最普及的無狀態身分驗證標準,但也是 OWASP Top 10 中最常被誤用的協定之一。從 QA 角度,理解 JWT 結構才能真正設計出有效的安全測試案例。

三段是什麼,為什麼這樣設計

JWT 用 . 切成三段,各自 Base64URL 編碼:

  • Header:{"alg":"HS256","typ":"JWT"} — 演算法與型別
  • Payload:{"sub":"123","exp":1700000000,"role":"admin"} — claims(主體、過期時間、自訂欄位)
  • Signature:用 header 指定的演算法,把 header.payload 拿 secret(HS256)或 private key(RS256)簽出來

設計上 header / payload 沒有加密(只有編碼),任何人都能 Base64 解開看內容。真正的安全來自 signature:驗證方用 secret / public key 重算一次 signature,跟 token 帶來的比對,只要 payload 被改過,signature 就對不上。

HS256 vs RS256 vs ES256:什麼時候用哪個

  • HS256(對稱):快、實作簡單,但簽章方跟驗證方共用同一個 secret。適合單一服務內部(API gateway → 自己的 backend)。
  • RS256(非對稱 RSA):簽章用 private key、驗證用 public key。適合一對多場景(Auth server 發 token,多個 microservice 驗)。public key 可公開,各服務不會互相洩漏。
  • ES256(非對稱 ECDSA):跟 RS256 同概念,但簽章短、計算快 80% 以上。新專案建議用這個

WebCrypto / Node 標準函式庫都原生支援這三種。

三個必修漏洞

1. alg: none 攻擊:有的舊版 library 接受 {"alg":"none"} header,意思是「不驗 signature」。攻擊者改 payload 後把 signature 段留空,系統直接放行。

2. 演算法混淆(RS256 → HS256):server 預期收 RS256,但攻擊者把 header 改成 alg: HS256,然後用 public key 當 secret 重簽。某些 library 沒檢查 alg 一致性,public key 又是公開的,token 就被驗過。

3. 沒驗 exp / aud:大量 QA 流程只驗 signature 正不正確,忘了:

  • exp claim 過期沒
  • aud claim 是不是給這個服務(prevent token reuse)
  • iss claim 來源對不對

設計測試案例時,這三條每條都要有獨立的負面測試

客戶端怎麼存 token(三選一,各有風險)

  • localStorage:最方便,但 XSS 一發就完蛋(惡意 script 直接讀走)。
  • httpOnly + Secure + SameSite=Strict cookie:擋住 XSS,但 CSRF 風險(需配合 CSRF token 或 SameSite=Lax + 雙重驗證)。
  • In-memory(React state):最安全,但刷新分頁就沒了(需要 refresh token 從 httpOnly cookie 重拿)。

業界主流:access token in memory + refresh token in httpOnly cookie,這套對 XSS 和 CSRF 都有相對好的防禦。

JWT 測試清單(QA 用)

正面測試:

  • 合法 token → 200
  • payload 內含的 role / scope 真的影響回傳內容

負面測試(這些 case 沒寫等於系統有漏洞):

  • 過期 token → 401
  • 簽章被竄改的 token → 401
  • alg: none header → 401(不能是 200)
  • 拿 A service 的 token 打 B service → 401(aud 驗證)
  • 用 public key 當 secret 重簽 HS256 → 401(演算法混淆防禦)
  • 把 payload 內的 roleuser 改成 admin(但 signature 不改)→ 401

上面這套用 JWT decoder / generator 工具 都能手動模擬。

想實際試一下?用 JWT 工具 的 Sign 模式偽造一個 alg: none 或過期 token,丟給你的 API 看擋不擋得住。

搭配工具
JWT decoder / generator
開啟工具