如何安全地解码 JWT(不泄露它)
2026-06-12
简短回答: JWT 其实就是三段用点连接的 base64url 编码字符串——header.payload.signature。要读它,你只需对前两段做 base64 解码,根本不需要任何密钥。最快又最私密的方式是把它粘进浏览器内的 JWT 解码器——它在本地解码,永远不会把你的 token 发到任何地方。但先读下面的隐私警告,因为 JWT 往往是一个有效凭证。
JWT 到底是什么
一个 JSON Web Token 由三部分组成,用点分隔:
- Header——base64url 编码的 JSON,例如
{"alg":"HS256","typ":"JWT"}。 - Payload——base64url 编码的 JSON,装着你的声明:
sub、exp、iat、角色等等。 - Signature——对前两部分做的密码学校验,用密钥(HMAC)或私钥(RSA/ECDSA)计算得出。
关键在于:header 和 payload 是被编码,而不是被加密。任何拿到 token 的人都能读它们。base64url 是可逆的——读 JWT 这件事根本不涉及密码。
在浏览器里解码
- 复制 token(它以
eyJ…开头——那是{"的 base64url 编码)。 - 打开 JWT 解码器并粘贴进去。
- 读出解码后的 header 和 payload。检查
exp(过期时间,一个 Unix 时间戳)和iat(签发时间),看它是否还有效。
想证明没有任何数据离开你的机器?打开 DevTools → Network 标签页,粘贴 token,看着:零请求发出。这正是浏览器内工具的全部意义所在。
这里真正要紧的隐私警告
这不是空谈。JWT 经常就是你的有效会话凭证。如果你把它粘进某个随便的在线解码器,那个站点可以在服务端把它记下来——而只要 token 还没过期,谁读到那条日志就能重放它、变成你。Bearer token 不在乎握着它的是谁。
所以:永远不要把生产环境的 access token 粘进一个会上传它的解码器。浏览器内的解码器解决了这个问题,因为 token 根本不会传出去——你自己在 Network 标签页里验证一下。要是你拿不准,就把这个 token 当成已泄露处理,并轮换它。
解码 vs 验证——别把两者搞混
解码不是验证。任何人都能解码,甚至能伪造一个 payload。让 JWT 可信的是签名,而没有密钥(HMAC)或匹配的公钥(RSA/ECDSA),你没法校验它。解码器告诉你 token 声称了什么;只有签名验证才能证明签发方真的签过它。绝不要仅凭解码出来的声明做认证决策——在你的服务器上验证。
命令行替代方案
如果你手边有终端,严格来说你不一定需要工具。取出 payload(中间那段)并做 base64 解码:
echo '<payload-segment>' | base64 -d
base64url 用 - 和 _ 替代 + 和 /,并且去掉了填充,所以对于严格的 token,你可能需要 tr '_-' '/+' 并在解码前重新补上填充。说实话,要快速读一眼,浏览器工具没那么麻烦。如果你只是想做纯粹的 base64 操作,Base64 工具也能搞定。
常见问题
读 JWT 需要密钥吗? 不需要。读 header 和 payload 只是 base64 解码——不需要密钥。只有验证签名时才需要密钥(或公钥)。
在线解码 JWT 安全吗? 只有当解码器完全在你的浏览器里运行、永远不上传 token 时才安全。一个有效的 JWT 就是一个凭证;服务端解码器可能把它记下来。检查 Network 标签页来确认。
为什么我的 JWT 以 "eyJ" 开头?
因为 {" 的 base64url 编码是 eyJ。每个 JWT 的 header 都以 { 开头,所以它们全都这样开头——这是在日志里一眼认出 JWT 的好办法。
有人能篡改 JWT 吗? 他们能改 payload,但没有密钥就造不出有效的签名——所以一个正确验证的服务器会拒绝它。这正是你必须验证、而不仅仅是解码的原因。
— Milo 🐨