简体中文

解码后的 JWT 证明了什么

JWT 解码器向您显示令牌声明的内容。它无法向您表明这些说法是否属实。本指南介绍了这三个部分是什么、解码做什么和不做什么,以及存在于两者之间的攻击。

三个段,其中两个只是 JSON

JWT 的常见形式是 JWS:由点分隔的三个 base64url 段。第一个是标头,第二个是有效负载,第三个是签名。

标头和负载是经过 base64url 编码的普通 JSON 对象。已编码,未加密。任何持有令牌的人都可以立即读取两者,无需密钥——这不是缺陷,而是设计。 JWT 是一份签署的声明,而不是密封的信封。签名保证该声明未被更改;它没有任何作用来保持其私密性。

结果值得明确说明,因为它经常被忽略:永远不要在 JWT 有效负载中放入任何机密内容。不是密码,不是完整的国家标识符,也不是内部系统详细信息。假设有效负载是公开的,因为对于拥有令牌的任何人来说,它都是公开的。

第三段是签名,根据前两段计算得出。它是唯一具有任何安全价值的部分,并且是解码器无法评估的部分。

解码证明什么:什么都没有

这是整个指南的重点。解码 JWT 会将两个 base64url 字符串解析为 JSON。它确认令牌的格式良好。它不确认该令牌是真实的,它是由“iss”声明中指定的一方颁发的,该声明未经编辑,或者它曾经有效。

任何人都可以构建代币。获取任何 JWT,将“角色”:“用户”更改为“角色”:“管理员”,重新编码有效负载,在末尾装订任何签名,解码器将像显示原始内容一样自信地显示您编辑的声明。它无法知道差异,因为检查差异是一个不同的操作,需要解码器没有的密钥。

因此,当解码器(这个解码器或任何其他解码器)向您显示“exp: 2026-01-01”时,它真正告诉您的是:此令牌包含一个在该日期到期的声明。该声明是否有意义完全取决于签名是否有效,而签名尚未经过检查。

该工具仅进行解码,并且每次都会在页面结果旁边注明。不在脚注中。原因是对此保持沉默的解码器正在训练其用户读取未经验证的数据,就像它已被验证一样,而这种习惯是整个身份验证错误家族的根源。

为什么这个工具不提供验证

验证需要网页不能负责任地拥有的三样东西:发行者的密钥、预先固定的算法以及关于拒绝什么的策略。

关键是显而易见的问题。对于 HMAC 算法(HS256 和类似算法),密钥是一个共享秘密——与创建令牌相同的秘密。将其粘贴到网页中意味着将可以生成有效令牌的凭证粘贴到网页中。对于 RSA 和 ECDSA,公钥不是秘密的,但您仍然需要从正确的 JWKS 端点获取正确的公钥并信任您所拥有的。

该算法是一个微妙的问题,也是两次著名攻击的根源。第一个是 alg: "none":标头声明令牌未签名,并且尊重标头而不是其自己的配置的验证程序接受任何内容。第二个是 RS256 到 HS256 的混淆:攻击者获取公钥(根据定义,即公共密钥)将标头更改为 HS256,并使用该公钥作为 HMAC 密钥对令牌进行签名。从令牌中读取算法并查找“密钥”的验证者将对其进行验证。

这两种攻击都源于同一个错误:让令牌告诉验证者如何检查令牌。正确的验证程序会忽略标头的算法并使用其配置的算法。这是属于信任令牌的系统的决定,而不是便利工具的决定,也不是将某些内容粘贴到表单中的人的决定。

为什么不将生产令牌粘贴到任何地方

访问令牌是不记名凭证。这就是授权标头中“承载者”的含义:无论谁承载它,就是您。没有第二个因素,通常也没有办法区分被盗令牌和合法令牌。在过期之前,它是您帐户的工作密钥。

因此,将实时令牌粘贴到任何网页中就是向该页面传递凭证。这个在本地解码所有内容,并且在页面加载后不发出网络请求 - 您可以在浏览器的网络面板中确认这一点,而且您应该这样做,因为这需要十秒钟。但请注意这个论点实际上是什么:在网站上声称该网站是值得信赖的。每个窃取代币的网站都提出完全相同的主张,访问者一眼无法看出区别。

安全习惯并不取决于正确判断地点。使用过期的令牌、测试环境令牌或您为此目的铸造的令牌。如果您已经将生产令牌粘贴到某处(任何地方),请旋转它。撤销的成本很低;事件不是。

这同样适用于签名密钥。没有正当理由在网页中输入 HMAC 秘密或私钥,任何要求“验证”您的令牌的网站都要求具有伪造令牌的能力。这就是该工具没有验证功能的具体原因:该功能需要请求。

阅读重要的声明

RFC 7519 注册一小组声明名称。 “iss”是发行者,“sub”是代币的主题,“aud”是目标受众,“exp”是到期时间,“nbf”是最早有效时间,“iat”是发行时间,“jti”是用于重放检测的唯一ID。其他一切都是特定于应用程序的。

时间声明是 NumericDate 值:自 Unix 纪元以来的秒数,而不是毫秒。这常常让人感到困惑,因为大多数 JavaScript 时间值都是毫秒。似乎在 1970 内到期的令牌通常会被赋予一个毫秒值;看起来在 55000 年到期的一个通常在某个地方有第二个值乘以 1000 。

当您调试时,“aud”值得特别注意。完全有效的令牌仍然可能是错误的令牌,因为它是为不同的受众发行的。检查签名但不检查受众的验证者将接受完全为另一个服务铸造的令牌——这是共享身份提供者的系统中真正的特权升级路径。

该工具以 UTC 格式呈现时间声明,将过期令牌标记为已过期,并将其与提醒配对,即过期声明仅在签名有效时才有意义。之所以有提醒,是因为“它说它尚未过期”正是未经验证的数据习惯造成损害的时刻。

进行信任的系统的简短清单

如果您正在编写接受令牌而不仅仅是检查令牌的代码,则以下是正确验证程序所做操作的简短版本。

  1. 在阅读任何声明之前,请先使用您从带外获得的密钥验证签名。
  2. 将算法固定在您自己的配置中。切勿从令牌标头中读取它。无条件拒绝“无”。
  3. 根据可信时钟检查“exp”和“nbf”,最多允许较小的偏差。
  4. 根据您期望的值检查“iss”和“aud”。令牌上的有效签名对于其他人来说仍然是错误的令牌。
  5. 使用适合您的平台的经过审查的库,而不是自己组装。此列表中的每一项都在其中,因为实现中出现了错误。
  6. 保持令牌生命周期较短,并具有撤销路径。短暂的令牌可以限制您尚未注意到的泄漏造成的损害。

你粘贴的内容会发生什么

  • 每个转换、哈希、解码和差异都在您的浏览器选项卡中运行。不会在服务器上上传、记录或存储任何输入,因为页面加载后就不再涉及服务器。
  • 哈希值来自浏览器自己的 Web Crypto 实现,UUID 来自其加密安全随机生成器。两者都不涉及网络调用。
  • 您键入的任何内容都不会写入本地存储或 cookie。重新加载页面会丢弃它;关闭选项卡将丢弃它。
  • 站点范围的分析仅在配置的规范生产主机上运行,并在隐私政策中披露;本地和预览主机拒绝它。粘贴的值、令牌、URL 和文件内容不包括在 ToolAcre 自己的分析事件中。当前配置中禁用广告。
  • 也就是说:JWT 或 API 密钥是实时凭证。安全的习惯是永远不要将其粘贴到不是您编写的网页中,无论其声明多么可信 - 包括这个。

问题

这个工具可以验证签名吗?

不,而且永远不会。它对标头和有效负载进行解码并显示它们包含的内容。它不检查签名,因此它显示的任何内容都无法证明令牌是真实的、未更改的或由其指定的任何人颁发的。

那么我怎么知道令牌是真的呢?

通过使用发行者的密钥验证签名,使用经过审查的库,并将算法固定在您自己的配置中,而不是从令牌中读取。这是在合法持有密钥的环境中信任令牌的服务的工作。

当我在这里解码时,我的令牌会发送到任何地方吗?

不会。解码使用页面自己的 JavaScript 在浏览器选项卡中进行,并且页面加载后不会发出网络请求。您可以在浏览器的网络面板中验证这一点。您仍然不应该将生产令牌粘贴到网络工具中作为一种习惯,因为这种习惯必须在不诚实的网站上起作用。

为什么任何人都可以读取我的 JWT 有效负载?

因为有效负载是 base64url 编码的,而不是加密的。 JWS 是一份签署的声明,而不是密封的声明。如果您需要使内容不可读,则需要 JWE(加密令牌格式),然后解码器在没有密钥的情况下根本无法向您显示任何内容。

alg:“无”是什么?

声明令牌未签名的标头值。它存在于通过其他方式保证完整性的上下文规范中,并且它是一个长期陷阱:信任标头算法的验证者将接受任何声称“无”的令牌。该工具每当它出现时都会对其进行标记。

我的令牌有五个段,无法解码。为什么?

五个段意味着一个 JWE(一种加密令牌),而不是一个签名的 JWS。如果没有解密密钥就无法读取其内容,因此解码器实际上无法显示任何内容。该工具明确识别该情况,而不是报告模糊的解析失败。

到期时间看起来有 1000 的错误。

JWT 时间声明是 NumericDate:自纪元以来的秒数,而不是毫秒。 Date.now() 生成的值太大了一千倍。该工具包中的时间戳实用程序在两者之间进行转换,并始终告诉您它使用的单位。

将 JWT 存储在 localStorage 中安全吗?

这是一种权衡,而不是是或否。 localStorage 可由在您的源上运行的任何 JavaScript 读取,因此单个 XSS 漏洞就会泄露令牌。 httpOnly cookie 无法被 JavaScript 读取,但需要 CSRF 保护。诚实的总结是,两者都不是免费的,决定取决于应用程序的威胁模型。

局限性

  • 该工具仅解码。它不验证签名,这是一个永久性的设计决策,而不是一个缺失的功能——请参阅上面的指南了解原因。
  • 如果没有密钥,加密令牌(JWE,五个段)根本无法解码。该工具识别出它们并停止。
  • 嵌套 JWT(有效负载本身就是令牌的令牌)不会自动解包。解码内部令牌作为一个单独的步骤。
  • RFC 7519 中定义的注册集之外的声明含义是特定于应用程序的,因此该工具会显示它们的值而不解释它们。
  • 此处显示的到期时间仅反映令牌对其自身的声明。该声明是否有意义取决于该工具不检查的签名。
  • 大于 200,000 个字符的令牌将被拒绝。任何真正的 JWT 都要小几个数量级。