名詞解釋

JWT(JSON Web Token)是什麼?帶簽章權杖的原理與安全用法

JWT(JSON Web Token)是伺服器簽章後發放、可察覺竄改的權杖。從防禦視角說明三部分結構,以及不校驗簽章、允許 alg:none、內容放機密、有效期過長等常見風險的防禦方法。

發布於 2026-06-12 更新於 2026-10-06 閱讀時間 2 分鐘
本頁內容

登入後由伺服器交給你的帶簽章權杖,就是 JWT。本文講解它的原理以及安全使用的關鍵要點(不會寫出攻擊手法)。

原理(三個部分)

JWT 是用 . 把 標頭.酬載.簽章 三部分連接而成的字串。標頭和酬載只是用 base64url 編碼(並非加密),只有簽章是用金鑰(或共用金鑰)生成的。

① 標頭

簽章演算法等元資訊。任何人都能讀

② 酬載

使用者 ID、有效期等主張。任何人都能讀=不要放機密

③ 簽章

用金鑰生成。保證未被竄改

JWT 由三部分組成。標頭和酬載「只是可讀」,真品保證由簽章承擔。

內容「只是可讀」這一點至關重要。所以酬載不是放密碼或個人資訊的地方。JWT 的價值在於:伺服器透過校驗簽章,就能確認「這個權杖是我簽發的、且未被竄改」。

安全使用的防禦措施

1

必須校驗簽章,並固定 alg(最重要)

在伺服器端每次都校驗簽章。把允許接受的簽章演算法(alg)固定為期望的值,並拒絕 alg:none(無簽章)。不要輕信權杖標頭裡寫的 alg。

2

不要把機密放進酬載

要以"內容人人都能解碼"為前提。密碼、個人資訊、API 金鑰等機密不要放進去。只放識別碼或權限等即便外洩也不致命的主張。

3

把有效期設短,並準備失效手段

存取用權杖要設為短命。過長的有效期會延長權杖被盜後的受害時間。如果設計上需要失效,就把短命的存取權杖+伺服器端管理的刷新/工作階段搭配使用。

4

使用強金鑰,並存放在不會被盜的地方

簽章金鑰要足夠強,不要重複使用,並保管在伺服器端的安全位置。權杖本身也要連同保管與傳輸一起守護,比如不被 XSS 竊取、用帶安全屬性的 Cookie 傳輸(→ 注意經由 XSS 的竊取)。

本站觀點:JWT 並不適合當作所有用途的工作階段機制

JWT 常被用於「保存登入狀態」,但它有一個弱點:不易讓它失效。只要簽章正確且在有效期內,伺服器基本上就會信任它,因此很難讓登出或失效立即生效。

本站的立場是:不要把 JWT 當作長期有效的工作階段替代品。把短命的存取權杖,與伺服器端可撤銷的刷新/工作階段組合起來,就能兼顧 JWT 的優點(校驗輕量)和失效的便利性。

注意:「能解碼」不等於「正確」

JWT 的內容是可讀的,所以只要貼進 JWT 解碼器,任何人都能查看標頭和酬載。但是解碼(讀取內容)與校驗(確認真偽)完全是兩回事。能解碼並不能保證任何正確性。判定權杖真偽的,永遠是伺服器端的簽章校驗。除錯時查看內容很方便,但請不要誤以為「能讀出來就有效」。

JWT 與伺服器端工作階段(Cookie)的比較

JWT 只是保存登入狀態的方法之一,有些情況比伺服器端工作階段適合,有些情況則不然。

項目伺服器端工作階段(Cookie)JWT
狀態存在哪裡伺服器上(DB 或記憶體);Cookie 只放 ID權杖內;伺服器只校驗簽章
登出/停權在伺服器上刪除即立即生效除非另外建立撤銷機制,否則在到期前都會被接受
內容的可見性只有 ID,沒什麼可讀任何人都能解碼讀取
適合的情況單一網域上的一般 Web 應用多個服務或 API 校驗同一個權杖

只在單一網域上運作的 Web 應用,伺服器端工作階段往往就足夠。如果選擇 JWT,在登入時發出全新的權杖,與防範工作階段固定是同一個原則。

實際案例:沒有檢查演算法的函式庫

演算法的切換並不只是理論。被廣泛使用的 Node.js JWT 函式庫 jsonwebtoken,在 4.2.1 以前的版本沒有正確檢查權杖標頭中指定的演算法,導致校驗可被繞過(CVE-2015-9235,已在 4.2.2 修正)。原本該用公開金鑰校驗的權杖,改用共用金鑰(HS 系列)演算法簽章後仍會通過——正是上面所說的演算法混淆。

兩個教訓:

  • 保持函式庫為最新版本。把 lockfile 貼到相依套件漏洞掃描器,就能確認相依套件中的已知漏洞
  • 不要依賴函式庫的預設值,在自己的程式碼中明確寫出允許的演算法

如何檢查自己的權杖

把自己的服務發出的權杖貼到 JWT 解碼器,查看以下各點。解碼在瀏覽器中執行,權杖不會被送到伺服器。即便如此,若是正式環境中仍有效的權杖,事後登出讓它失效比較妥當。

  1. 標頭的 alg 是否為預期的值(不是 none)?
  2. 是否有 exp,從 iat(簽發時間)算起的有效期是否符合用途?
  3. 是否有 aud 與 iss,並且指向你的服務?
  4. 酬載中是否含有不想被看到的東西——電子郵件地址、電話號碼、API 金鑰?

伺服器端的校驗,請在開發環境用測試確認。簽章被改了一個字元的權杖、alg 不同的權杖、已過期的權杖,以及給其他服務用的權杖(aud 不符)都應該被拒絕——把這些保留為自動化測試。

出處(一手資料)

  • IETF RFC 8725, "JSON Web Token Best Current Practices" — datatracker.ietf.org(固定演算法、校驗所有密碼學運算、演算法混淆、金鑰屬於簽發者)
  • IETF RFC 7519, "JSON Web Token (JWT)" — datatracker.ietf.org(exp、nbf、aud 的規範定義)
  • GitHub Advisory Database, "Verification Bypass in jsonwebtoken"(CVE-2015-9235)— github.com/advisories(4.2.1 以前受影響;4.2.2 修正)
  • OWASP HTML5 Security Cheat Sheet — cheatsheetseries.owasp.org(不要把工作階段識別碼存進 localStorage)

接下來閱讀

FAQ

QJWT 的內容是加密的嗎?
A

不是。標準 JWT 的標頭和酬載並非加密,只是用 base64url 做了「編碼」,任何持有權杖的人都能讀到裡面的內容。所以絕不能把密碼、個人資訊等機密放進酬載。JWT 保護的不是「內容的機密性」,而是「未被竄改(靠簽章保證的完整性)」。

QJWT 中最危險的設定是什麼?
A

不校驗簽章,或者接受「alg:none(無簽章)」的實作。一旦允許,攻擊者就能讓自己隨意改寫內容的偽造權杖通過。防禦方法是:在伺服器端必須校驗簽章,並把允許接受的簽章演算法(alg)固定為期望的值。

Q解碼和校驗一樣嗎?
A

不一樣。解碼只是讀取內容,任何人都能做(用 JWT 解碼器即可查看)。校驗則是伺服器用金鑰/公開金鑰確認簽章是否正確、是否在有效期內、簽發者和受眾是否正確的處理過程。「能解碼=就是正確的權杖」是錯誤的。判定真偽的永遠是伺服器端的校驗。

Q該用 JWT 還是工作階段(Cookie)?
A

在單一網域上的一般 Web 應用,伺服器端工作階段搭配 Cookie 往往就足夠,而且登出或停權能立即生效。JWT 適合多個服務或 API 校驗同一個權杖,或從外部身分提供者(OAuth/OpenID Connect)接收權杖的情況。如果使用 JWT,請把有效期設短,並搭配伺服器能撤銷的機制。

Q可以把 JWT 存在 localStorage 嗎?
A

不建議。localStorage 永遠可被 JavaScript 讀取,只要有一個 XSS 漏洞,攻擊者就能偷走權杖。OWASP 也建議不要把工作階段識別碼存進 localStorage。在瀏覽器中,用帶有 HttpOnly、Secure 與 SameSite 的 Cookie 攜帶權杖比較安全;若使用 Cookie,也要加上 CSRF 防護。

QJWT 的「alg:none」是什麼?
A

就是標頭中把 alg(簽章演算法)設為 none、也就是沒有簽章的 JWT。規格上允許它,但登入等用於認證的權杖絕不能接受它;否則任何人都能製作內容被改寫的權杖。防止方法是在伺服器端把允許的演算法固定為期望的值(例如只允許 RS256)。