跳到主要內容

JWT 解碼器 — token 不離開瀏覽器

貼上 JWT,立刻看到 header、payload 與每個 claim 的意思,過期時間自動換算成當地時間。全程在瀏覽器內解碼,token 不上傳。 排查線上問題時貼進來的往往是某個真實使用者的憑證,裡面有 user ID、權限甚至 email,所以這一頁不設後端,解碼與驗簽都在你的分頁裡跑完。

什麼時候會需要拆開一個 token

  • API 一直回 401,要確認是 token 過期了,還是根本沒帶到你以為的那個權限。
  • 使用者回報「莫名其妙被登出」,要看這張 token 的有效期到底設了多久。
  • 串接第三方登入,想確認對方回傳的 payload 裡到底有哪些欄位可以用。
  • 前後端對不上時區,要把 exp 那串秒數換算成看得懂的當地時間。
  • 做安全檢查,想確認自家簽出去的 token 有沒有把不該放的個人資料寫進 payload。

JWT 的三段結構

一個 JWT 就是三段 Base64URL 用點號接起來的字串,形如xxxxx.yyyyy.zzzzz。工具的結果區把這三段染成三個顏色, 對照下面這張表就知道每一段在做什麼。

段落內容能不能被讀懂
Header一個 JSON 物件,說明用哪種演算法簽的(alg)、這是什麼型別的 token(typ),有時還有金鑰編號(kid)。可以,任何人都讀得到。
Payload一個 JSON 物件,裝的是這個 token 想主張的事情,每一個欄位叫一個 claim,例如使用者是誰、有什麼權限、什麼時候過期。可以,任何人都讀得到。
Signature前兩段加上密鑰算出來的雜湊值。它不含任何資訊,唯一的用途是證明前兩段 沒有被改過。不行,它本來就不是拿來讀的。

七個註冊 claim 各代表什麼

RFC 7519 定義了七個標準 claim,名字都很短,第一次看不容易猜。工具的 claim 對照表會把說明直接列在欄位旁邊,這裡是完整版。

Claim全名意思
issIssuer誰簽發了這個 token,通常是你的認證服務網址。
subSubject這個 token 在描述誰,多半是使用者 ID。
audAudience這個 token 是給哪個服務用的。收到不是給自己的 token 應該拒絕。
expExpiration Time到期時間。到了這個時間點之後,驗證方就該拒絕它。
nbfNot Before生效時間。在這之前這個 token 不該被接受。
iatIssued At簽發時間。拿它跟 exp 相減,就是這個 token 打算活多久。
jtiJWT ID這一張 token 的唯一識別碼,用來做撤銷清單或防止重放。

時間為什麼要換算,怎麼換算

  • 這三個時間 claim 的值是 NumericDate,也就是自 1970 年 1 月 1 日 UTC 起算的秒數,不是毫秒。JavaScript 的Date.now() 給的是毫秒,兩者差 1000 倍,是最常見的錯誤來源。
  • 秒數本身不帶時區。工具會同時顯示你這台電腦當地時區的時間與 ISO 8601 的 UTC 時間,前後端記錄對不上時,看這兩行就知道差了幾個小時。
  • 有效狀態分成四種:目前有效、已過期、尚未生效(nbf 還沒到), 以及沒有設定到期時間。最後一種本身就值得警覺,一張永不過期的 token 一旦外流就收不回來。
  • 剛簽出來就顯示「尚未生效」通常是伺服器之間的時鐘差異,多數函式庫允許幾十秒的 容許誤差,這個工具照字面判斷、不自己加容許值。

為什麼不要把敏感資料放進 payload

這是使用 JWT 最常見的誤解:Base64URL 是編碼,不是加密。 它沒有密鑰、不需要破解,任何拿到 token 的人都能像這個工具一樣把 payload 還原成 明文 JSON。簽章保護的是「內容有沒有被改過」,不是「內容能不能被看到」。

  • 不要放身分證字號、完整生日、住址、電話這類個資。
  • 不要放密碼、其他系統的 API key,或任何一組還能用的憑證。
  • email 與姓名要放之前先想清楚:token 常常被寫進伺服器日誌、錯誤回報系統與瀏覽器的 儲存空間,等於這些欄位也跟著被複製到那些地方。
  • 真的需要藏起來的內容要用 JWE,那是加密過的另一種格式,不是這裡處理的 JWS。
  • payload 只放識別碼,真正的資料讓後端自己去查,是比較安全的做法。

這裡驗得了哪些簽章

填入 HMAC 密鑰之後,可以離線驗證 HS256HS384HS512,用的是瀏覽器內建的 Web Crypto,密鑰不會離開這個分頁。

  • 驗證成功代表這個 token 確實是用該密鑰簽的,而且前兩段一個字都沒被改過。
  • 驗證失敗只有兩種可能:密鑰打錯,或這張 token 被動過手腳。
  • 有些服務後台給的密鑰是 Base64 編碼過的位元組,直接當文字算會得到不同的簽章, 這時勾選「密鑰是 Base64 編碼」。
  • RS256 這類非對稱演算法需要公鑰,抓公鑰要發跨網域請求而通常被 CORS 擋, 所以這裡不支援,也不會為此加轉送伺服器。

你貼上的 token 會不會離開瀏覽器

不會。解碼、時間換算與 HMAC 驗證都在你的瀏覽器裡完成,沒有任何請求會把 token 或密鑰 送出去,也不寫進瀏覽器的儲存空間,關掉分頁就沒了。匯出的解析報告刻意不含完整的 token,因為報告是拿去貼給別人看的,而 token 本身就是一組還能用的憑證。 細節見隱私權政策

常見問題

我貼進去的 token 會不會被送到伺服器?
不會。這個站沒有後端,解碼、時間換算與簽章驗證都是在你這個分頁的 JavaScript 裡跑完的。想自己確認的話按 F12 打開開發者工具的網路分頁,貼一次 token,你會看到沒有任何請求被發出去。
解碼跟驗證簽章差在哪裡?
解碼只是把 Base64URL 還原成 JSON,任何拿到 token 的人都做得到,它證明不了內容沒被改過。驗證簽章是拿密鑰重算一次雜湊再比對,那才能證明這個 token 確實出自持有該密鑰的一方,而且一個字都沒被動過。
為什麼 RS256 這類演算法在這裡驗不了?
RS、ES、PS 系列用的是非對稱金鑰,驗證需要簽發方的公鑰,而公鑰通常掛在對方的 JWKS 網址上。要抓那個網址就得從瀏覽器發跨網域請求,多半會被 CORS 擋掉。與其做一個時靈時不靈的功能,這裡選擇只支援 HMAC,也不會為此加轉送伺服器。
exp 顯示的時間跟我後端記的差了好幾個小時?
那是時區,不是算錯。JWT 的時間是自 1970 年起算的 UTC 秒數,本身不帶時區。這個工具同時顯示你電腦當地時區的時間與 ISO 8601 的 UTC 時間,兩個對照就看得出差幾個小時。另外注意單位是秒不是毫秒,用毫秒去算會差 1000 倍。
可以在這裡修改 payload 再簽一次嗎?
不行,這個工具只讀不寫。改過 payload 的 token 一定要用原本的密鑰重新簽章才會被接受,而那組密鑰應該只存在你的伺服器上,不該貼到任何網頁裡。