免费 JWT 解码器
解码并查看 JSON Web Token · header、payload、claims 和过期时间。
Header
Payload
Signature
关于 JWT
JSON Web Token (JWT) 是一种用于在两方之间紧凑表达声明的方式。它由三部分组成:header(算法和类型)、payload(如签发者、过期时间、subject 等声明)和 signature。本工具仅解码 header 和 payload,不验证签名 · 验证签名需要签名密钥或公钥。所有解码都在您的浏览器中进行;您的令牌不会被发送到任何地方。
JSON Web Token 简史
JSON Web Token(JWT)于 2015 年 5 月由 Michael B. Jones(微软)、John Bradley(Ping Identity)和 Nat Sakimura(NRI)在 IETF 的 JOSE 工作组下标准化为 RFC 7519。这是半个十年工作的顶点:第一份 JWT 互联网草案出现于 2010 年 12 月,源于 SAML 2.0(2005)笨重的基于 XML 的断言格式,以及对浏览器可以原生解析的更轻量替代品的强烈需求。突破在于选择 JSON 而非 XML,base64url 而非 PEM:一个 JWT 可以放入 URL 查询字符串或 Authorization: Bearer 头部。整个 JOSE 系列作为协调的一组发布:RFC 7515(JWS)用于签名,RFC 7516(JWE)用于加密,RFC 7517(JWK)用于密钥格式,RFC 7518(JWA)用于算法标识符,以及 RFC 7519(JWT)用于声明层,全部于 2015 年 5 月同一天发布。采用是即时的。OAuth 2.0(RFC 6749,2012)已标准化访问令牌但保留其格式不透明;行业选择了 JWT。OpenID Connect(2014 年 12 月,OpenID 基金会)使 JWT 对 ID 令牌成为强制要求。到 2017 年,所有主要身份提供商(Auth0、Okta、Azure AD、AWS Cognito、Google Identity、Firebase Auth)都将 JWT 作为其原生会话格式发出。JWT.io,Auth0 于 2014 年推出的解码器网站,成为事实上的 JWT 调试工具,并帮助巩固了该格式在开发者心中的份额。两起安全事件塑造了现代威胁模型:Tim McLean 2015 年披露的 alg: none 绕过和 HS/RS 算法混淆攻击,以及 CVE-2022-21449(2022 年 4 月),Neil Madden 在 Java 15-18 ECDSA 验证器中的「Psychic Signatures」漏洞。两者都导致库默认加固:大多数现代库现在直接拒绝 alg: none 并固定预期算法,而不是从令牌头部读取。
JWT 的结构剖析
- 三个 base64url 编码段。JWT 是字符串
header.payload.signature:三段以点分隔,每段都用 base64url 编码。RFC 7519 称之为 JWT 紧凑序列化。整个内容可以放入 URL 或 HTTP 头部;这种紧凑性是设计目标,使 JWT 区别于基于 XML 的前辈如 SAML。 - 头部。一个小的 JSON 对象,通常包含两个字段:
alg(签名算法,例如 HS256、RS256、ES256)和typ(几乎总是「JWT」)。可选字段包括kid(用于密钥轮换的密钥标识符)和cty(嵌套令牌的内容类型)。头部告诉验证者如何验证签名;切勿单独信任它,始终在服务器端固定预期算法。 - 负载。一个 JSON 对象包含声明,关于主题的键值断言。RFC 7519 §4.1 保留七个标准声明:
iss(发行者)、sub(主题)、aud(受众)、exp(过期)、nbf(生效前)、iat(签发时间)和jti(唯一 JWT ID)。发行者可自由添加自定义声明。负载是签名但未加密的:任何持有令牌的人都可以读取它。 - 签名。头部和负载未被篡改的密码学证明。签名输入是字面字符串
base64url(header) + "." + base64url(payload);签名本身然后被 base64url 编码作为第三段。验证需要对称密钥(HS*)或非对称公钥(RS*、ES*、PS*、EdDSA),并且必须始终在受信任的服务器上进行。 - base64url,不是 base64。JWT 段使用 RFC 4648 §5 中定义的 URL 安全的 base64 变体:字符 62 是
-而不是+,字符 63 是_而不是/,并且去除尾部的=填充。JavaScript 的内置atob()只处理标准 base64,因此 JWT 解码器在解码前会翻译字母表并重新填充。 - NumericDate:秒,不是毫秒。RFC 7519 将
exp、nbf和iat定义为「自 1970-01-01T00:00:00Z UTC 起的秒数」。JavaScript 的Date.now()返回毫秒,因此一个常见的 bug 是exp大了三个数量级,产生一个「在 53000 年左右」过期的令牌。签发令牌时始终使用Math.floor(Date.now() / 1000)。
JWT 在实践中的使用场景
- OAuth 2.0 访问令牌。RFC 6749 保留了访问令牌格式不透明,但实际上行业标准化为 JWT。Auth0、Okta、Azure AD、AWS Cognito 和 Google Identity 都默认发出 JWT 访问令牌。你
Authorization头部中的 Bearer 令牌几乎总是一个 JWT。 - OpenID Connect ID 令牌。OIDC(2014 年 12 月)强制其
id_token使用 JWT。id_token携带关于已认证用户的身份声明(sub、email、name、picture),并由依赖方消费而不是向前传递。这是「使用 Google 登录」、「使用 Apple 登录」及类似流程背后的主要机制。 - API 认证。无状态 REST API 采用 JWT,因为它消除了对服务器端会话存储的需求:API 信任签名验证的内容。Stripe 风格的 API 密钥在服务器到服务器流量中仍然常见,但对于用户范围的 API,
Authorization: Bearer <jwt>模式现在是默认的。 - 微服务到微服务的认证。在 API 边缘签发的用户范围 JWT 通过内部服务到服务调用转发,使每个服务能够信任原始认证而无需重新认证。该模式有时被称为「令牌转换」:边缘网关将不透明会话交换为限定到下游调用的短期 JWT。
- 单页应用会话。SPA(React、Vue、Angular)历史上为了方便将访问令牌存储在
localStorage中。现代指导(OWASP、Auth0)是将访问令牌保留在内存中,将刷新令牌保留在HttpOnly + Secure + SameSite=Strictcookie 中,因为localStorage可被任何登陆页面的 XSS 读取。 - 移动应用会话。iOS 和 Android 应用将访问令牌存储在平台 Keychain 或 Keystore 中。令牌在每次后端调用时作为
Authorization: Bearer发送。刷新令牌在每次使用时轮换,访问令牌的短exp(通常 5-15 分钟)是抵御被盗设备重放的主要防御。
标准与安全里程碑
- RFC 7519(JWT,2015 年 5 月)。基础规范。定义了 JWT 紧凑序列化、七个标准注册声明(
iss、sub、aud、exp、nbf、iat、jti)和 NumericDate 格式。作者:Michael B. Jones、John Bradley、Nat Sakimura。 - RFC 7515(JWS,2015 年 5 月)。JSON Web Signature。几乎所有人非正式地称为「JWT」的签名包装格式:三个 base64url 段以点连接。JWS 支持紧凑和 JSON 序列化两种形式;JWT 仅使用紧凑形式。
- RFC 7516(JWE,2015 年 5 月)。JSON Web Encryption。加密变体,有五段(头部、加密密钥、IV、密文、认证标签)。当负载必须保密而不仅仅是防篡改时使用 JWE,而不是 JWS。
- RFC 7517(JWK,2015 年 5 月)。JSON Web Key。密码学密钥的 JSON 表示。JWKS 端点(
/.well-known/jwks.json)发布一个 JSON Web Key Set,是零停机密钥轮换的现代机制:验证者按kid查找密钥。 - RFC 7518(JWA,2015 年 5 月)。JSON Web Algorithms。
alg标识符注册表:HS256/384/512(HMAC)、RS256/384/512(RSASSA-PKCS1-v1_5)、ES256/384/512(ECDSA)、PS256/384/512(RSASSA-PSS)、EdDSA(Ed25519/Ed448)和(有意很少使用的)none。 alg: none绕过(Tim McLean,2015)。RFC 7518 将none列为非安全上下文的有效算法值。天真的验证者会接受头部被重写为{"alg":"none"}且签名为空的令牌,允许攻击者伪造任何负载。现代库默认拒绝none;规范本身指出验证者「默认不得接受非安全 JWS」。- HS/RS 算法混淆攻击(Tim McLean,2015)。如果验证者从令牌头部选择算法而不是固定它,攻击者可以将头部重写为
HS256并使用服务器的 RSA 公钥作为 HMAC 密钥签名令牌。库看到 HS256,将配置的 RSA 公钥视为对称密钥,签名验证通过。缓解措施:带外固定预期算法;切勿从令牌中派生。 - CVE-2022-21449「Psychic Signatures」(Neil Madden,2022 年 4 月)。Java 15-18 的 ECDSA 验证器没有检查签名的
r和s值是否非零,这意味着字面上全零的签名被接受为有效。在受影响的 JVM 上用 ES256/384/512 签名的 JWT 可以用空白签名伪造。在 Oracle 2022 年 4 月的关键补丁更新中修补。
更多常见问题
为什么这个工具不验证签名?
验证需要密钥(HMAC)或公钥(RSA / ECDSA / EdDSA)。将生产 HMAC 密钥粘贴到任何网站本身就是一次凭证泄漏,即使是一个发誓不传输任何东西的工具。验证属于你控制的服务器。解码器的工作是使内容可读,以便你看到验证器应该检查什么。
在这里粘贴真实的生产令牌安全吗?
解码完全在你的浏览器中进行。令牌不会通过网络发送,不会写入任何日志,也不会存储在任何地方。话虽如此,JWT 通常是一种凭证:任何持有未过期访问令牌的人都可以作为用户行事。社区惯例是「像对待会话 cookie 一样对待生产 JWT」:尽可能使用测试令牌,并轮换你在签发它的浏览器会话之外共享过的任何真实令牌。
我应该在浏览器中将 JWT 存储在哪里?
两种常见模式各有权衡。localStorage 方便但可被页面上任何成功的 XSS 攻击读取。带有 HttpOnly 的 Cookie 对 JavaScript 不可见,因此 XSS 无法读取它们,但需要 SameSite=Strict 或 SameSite=Lax 来避免 CSRF。当前的最佳实践:将短期访问令牌放在 JavaScript 变量中(仅内存),加上一个长期刷新令牌放在限定到刷新端点的 HttpOnly + Secure + SameSite=Strict cookie 中,每次使用都轮换。
头部中的 kid 字段做什么?
它标识签名令牌的密钥。现代身份提供商在 /.well-known/jwks.json 端点发布其公钥作为 JWK Set(RFC 7517);验证者查找其 kid 与令牌头部匹配的密钥。这就是零停机密钥轮换成为可能的原因:在宽限期内,旧密钥和新密钥都可以位于 JWKS 中。
我可以在 JWT 签发后撤销它吗?
本质上不能。签名的 JWT 在其 exp 声明之前都有效;这种无状态性是该格式的标志性属性。变通方法:保持访问令牌短(5-15 分钟)并配以可撤销的刷新令牌;维护服务器端已撤销 jti 值的拒绝列表;轮换签名密钥(这会使每个用它签名的未完成令牌失效)。每个选项都重新引入了一些状态;那就是权衡。
解码令牌与解密令牌是一回事吗?
不是。解码将 base64url 反转回 JSON:任何人都可以做,这就是重点。解密需要密钥,仅适用于 JSON Web Encryption(JWE,RFC 7516),即 JOSE 系列的加密变体。你在野外看到的大多数令牌是 JWS(已签名但未加密),所以解码足以读取它们。