为什么在JWT令牌中需要包含头部和载荷?

3
我相信我在这里忽略了非常简单的东西,但我刚开始学习JWT令牌进行身份验证,据我所知,JWT令牌的结构是:
Base64UrlEncode(Header) + '.' +  Base64UrlEncode(Payload) + '.' + CreateSignature(Header, Payload, Secret_Key)

我理解的是,您将此发送给客户端,并在需要时允许客户端将其发送回服务器。此时,您使用私钥解密签名以确保未被篡改。
我困惑的部分是,为什么您需要易于转换回纯文本的 Base64UrlEncode(Header) + '.' + Base64UrlEncode(Payload) + '.' 的第一部分呢?
既然您将在服务器上对其进行解密,那么您不能只传递签名,使用秘密键解密它并读取有效负载吗?这似乎更安全,因为第一部分可以轻松地转换回纯文本,并向攻击者提供存储在有效负载中的信息,例如 token expirationuserId 等。
我错过了什么吗?
1个回答

2
签名不包含有效载荷。签名可以简单地是JWT哈希(SHA256)的消息认证码(HMAC)。所以,如果您只发送签名,那将起到普通会话ID的作用,服务器仍然必须存储状态,抵消了JWT的任何好处。
您是正确的,JWT默认情况下未加密。虽然使用base64编码,但从安全角度来看,它就是纯文本,不应包含敏感(秘密)信息。签名提供的唯一保护是,当服务器收到它时,通过检查签名,可以确保jwt中的信息在客户端上没有被更改。
令牌未加密允许客户端检查其内容并找出例如到期时间、何时必须获取新令牌或已登录用户的ID等信息。持有jwt的用户将拥有此类信息,其他人不应该持有jwt,因为他们可以使用它进行身份验证以模拟用户。
但是,在特殊情况下,您可能仍希望包含敏感信息(即秘密),希望在服务器上接收到但不想向客户端披露。为此,您可以使用加密JWT(JWE)。缺点是,对于客户端来说,这个令牌将是不透明的,并且您可能需要实现应用程序端点来检索所有必要的信息。

谢谢,Gabor。我仍然困惑的部分是,我知道拥有未加密的数据可以让客户端获得一些信息,但更让我感到恐慌的是,这些数据将由客户端存储,如果黑客甚至获得一个已过期的令牌,他们可能会获取到用户ID或用户名等信息。 我不明白为什么你要把这部分作为安全令牌的一部分返回,而不是使用完全加密的令牌来回传(我猜你提到的是JWE)。我只是不明白其中的好处。 - undefined
就像我说的,我真的不明白为什么JWT的规范中会包含这一部分,而不仅仅是加密的最后一部分,并且将前两部分至少作为选择而不是约定。 但是,真的非常感谢你的解释! - undefined
2
单页JavaScript应用程序通常受益于具有纯文本数据,因为它们可以避免往返到服务器获取例如令牌寿命或用户ID。如果不使用这个,实际上可以选择加密JWT,而不仅仅是最后一部分,因为最后一部分只是一个固定长度的消息认证码(或签名,取决于所选择的算法)。与之相反,在加密JWT中,整个JWT(即实际数据)都被加密。 - undefined
2
是的,你说得对,如果客户端不需要从jwt中获取任何数据(这并不是典型情况),那么加密的jwt可能更安全。然而,相对于什么来说呢?jwt中典型包含的数据并不是真正敏感的,例如与实际用户共享userid在大多数应用程序中都是可以接受的。另一方面,加密会消耗资源 - 实际上是相当多的资源。此外,这将始终通过https发送 - 攻击者无法轻易获得甚至已过期的jwt,因此风险有限。 - undefined
完全同意。我只是觉得这似乎有些违反直觉,但我明白黑客获取JWT令牌是一件坏事 :) 非常感谢你在这个过程中花费的时间和解释! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接