如果你能解码JWT,它们的安全性如何?

如果我得到一个JWT并且我可以解码有效负载,这是安全的吗?难道我不能从报头中获取令牌,解码并更改有效负载中的用户信息,然后用相同的正确编码的秘密将其发送回来吗?

我知道它们一定很安全,但我真的很想了解这些技术。我错过了什么?

195503 次浏览

jwt既可以签名,也可以加密,或者两者都可以。如果一个令牌经过签名,但没有加密,那么每个人都可以读取它的内容,但是当您不知道私钥时,就不能更改它。否则,接收方将注意到签名不再匹配。

回答你的评论:我不确定我是否正确理解了你的评论。只是为了确定:你知道并理解数字签名吗?我将简单地解释一种变体(HMAC,它是对称的,但还有许多其他变体)。

让我们假设Alice想要发送一个JWT给Bob。他们都知道一些共同的秘密。马洛里不知道这个秘密,但想要干涉和改变JWT。为了防止这种情况,Alice计算Hash(payload + secret)并将其作为签名追加。

当Bob收到消息时,还可以计算Hash(payload + secret)来检查签名是否匹配。 然而,如果Mallory改变了内容中的某些内容,她就无法计算匹配的签名(这将是Hash(newContent + secret))。她不知道这个秘密,也没有办法知道。 这意味着如果她更改了某些内容,签名将不再匹配,Bob将不再接受JWT

让我们假设,我向另一个人发送消息{"id":1},并用Hash(content + secret)签名。(+在这里只是连接)。我使用SHA256哈希函数,我得到的签名是:330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c。现在轮到你了:扮演Mallory的角色,试着为消息{"id":2}签名。你不能,因为你不知道我用了哪个秘密。如果我假设接收者知道这个秘密,他可以计算任何消息的签名并检查它是否正确。

你可以去jwt.io,粘贴你的令牌并读取内容。一开始,这对很多人来说是不和谐的。

简而言之,智威汤逊并不关心加密问题。它关心验证。也就是说,它总是可以得到“这个令牌的内容被操纵了吗”的答案?这意味着用户对JWT令牌的操作是无效的,因为服务器将知道并忽略令牌。服务器在向客户端发出令牌时根据有效负载添加签名。随后,它验证有效载荷和匹配签名。

合乎逻辑的问题是,它不关心加密内容的动机是什么?

  1. 最简单的原因是因为它假设这在很大程度上是一个已经解决的问题。如果处理一个客户端,例如web浏览器,你可以将JWT令牌存储在secure(不通过HTTP传输,只通过HTTPS传输)和httpOnly(不能被Javascript读取)的cookie中,并通过加密通道(HTTPS)与服务器通信。一旦你知道你在服务器和客户端之间有一个安全的通道,你就可以安全地交换JWT或者其他你想要的东西。

  2. 这让事情变得简单。简单的实现使采用更容易,但它也让每一层都做自己最擅长的事情(让HTTPS处理加密)。

  3. JWT不是用来存储敏感数据的。一旦服务器接收到JWT令牌并对其进行验证,它就可以在自己的数据库中查找用户ID,以获得该用户的其他信息(如权限、邮政地址等)。这使JWT保持较小的规模,并避免了无意的信息泄漏,因为每个人都知道不要在JWT中保存敏感数据。

这与cookie本身的工作方式没有太大区别。cookie通常包含未加密的有效载荷。如果你使用的是HTTPS,那么一切都很好。如果不是,建议对敏感cookie本身进行加密。如果不这样做,就可能会受到中间人攻击——代理服务器或ISP读取cookie,然后假装是你,重新播放它们。出于类似的原因,JWT应该始终通过HTTPS之类的安全层进行交换。

json web令牌(JWT)中的内容本质上并不安全,但有一个内置的功能用于验证令牌的真实性。JWT是用句点分隔的三个散列。第三个是签名。在公钥/私钥系统中,颁发者使用私钥签署令牌签名,该私钥只能由其对应的公钥验证。

理解发布者和验证者之间的区别是很重要的。令牌的接收者负责验证它。

在web应用程序中安全地使用JWT有两个关键步骤:1)通过加密通道发送它们,2)在收到签名后立即验证签名。公钥密码学的非对称特性使得JWT签名验证成为可能。公钥验证JWT是由其匹配的私钥签署的。没有其他密钥组合可以执行此验证,因此可以防止模拟尝试。遵循这两个步骤,我们可以从数学上保证JWT的真实性。

更多阅读:公钥如何验证签名?

只有服务器上的JWT的privateKey才能解密加密的JWT。那些知道privateKey的人将能够解密加密的JWT。

将私钥隐藏在服务器的安全位置,并且永远不要告诉任何人私钥。

让我们从头开始讨论:

JWT是一种非常现代、简单和安全的方法,它扩展了Json Web令牌。Json Web令牌是一种无状态的身份验证解决方案。因此不需要在服务器上存储任何会话状态,这当然非常适合restful api。 Restful api应该始终是无状态的,使用jwt进行身份验证的最广泛的替代方法是使用会话在服务器上存储用户的登录状态。当然,它并没有遵循restful api应该是无状态的原则,这就是为什么像JWT这样的解决方案变得流行和有效的原因

现在让我们来了解一下Json Web Tokens的身份验证是如何工作的。假设我们的数据库中已经有一个注册用户。因此,用户的客户端首先发出带有用户名和密码的post请求,然后应用程序检查用户是否存在,如果密码正确,那么应用程序将仅为该用户生成一个唯一的Json Web Token。

令牌是使用秘密的字符串创建的,即存储在服务器上。接下来,服务器将JWT发送回客户端,客户端将其存储在cookie或本地存储中。 enter image description here < / p >

就像这样,用户通过身份验证并登录到我们的应用程序,而不会在服务器上留下任何状态。

所以服务器实际上不知道哪个用户实际登录了,但当然,用户知道他已经登录了,因为他有一个有效的Json Web Token,这有点像护照,可以访问应用程序的受保护部分。

再一次,为了确保你们理解了。一个用户一旦得到他唯一有效的Json Web令牌就登录了,这个令牌没有保存在服务器上的任何地方。所以这个过程是完全无状态的。

然后,每次用户想要访问一个受保护的路由,例如他的用户配置文件数据。他将他的Json Web Token与请求一起发送,所以这有点像出示他的护照来访问那条路线。

一旦请求到达服务器,我们的应用程序将验证Json Web令牌是否有效,如果用户确实是他所说的那个人,那么请求的数据将被发送到客户端,如果不是,那么将会有一个错误告诉用户他不允许访问该资源。 enter image description here < / p >

所有这些通信都必须通过https进行,所以安全加密的Http,以防止任何人可以访问密码或Json Web令牌。只有这样我们才有一个真正安全的系统。

enter image description here

因此,Json Web令牌看起来像这张截图的左边部分,这是从JWT调试器JWT .io中截取的。本质上,它是一个由三部分组成的编码字符串。标头,有效载荷和签名标头只是一些关于令牌本身的元数据有效载荷是我们可以编码到令牌中的数据,任何我们想要的数据。所以我们要编码的数据越多,JWT就越大。不管怎样,这两部分只是纯文本,会被编码,但不会加密。

所以任何人都能解码并阅读它们,我们不能在这里存储任何敏感数据。但这根本不是问题,因为在第三部分,在签名部分,才是真正有趣的地方。签名是使用头、有效负载和保存在服务器上的秘密创建的。

这整个过程被称为签署Json Web令牌。签名算法使用报头、有效负载和秘密来创建唯一的签名。所以只有这个数据加上这个秘密才能创建这个签名,对吧? 然后加上头部和有效载荷,这些签名形成了JWT, 然后被发送到客户端。 enter image description here < / p >

一旦服务器接收到JWT以授予对受保护路由的访问权,它就需要验证它,以确定用户是否真的是他所声称的那个人。换句话说,它将验证是否没有人更改标记的标头和有效负载数据。同样,此验证步骤将检查是否没有第三方实际更改Json Web Token的报头或有效负载。

那么,这种验证实际上是如何工作的呢?其实很简单。一旦接收到JWT,验证将使用它的头部和有效负载,以及仍然保存在服务器上的秘密,基本上创建一个测试签名。

但是当JWT第一次创建时生成的原始签名仍然在令牌中,对吗?这就是验证的关键。因为现在我们所要做的就是将测试签名与原始签名进行比较。 如果测试签名与原始签名相同,则意味着有效负载和报头没有被修改。 enter image description here < / p >

因为如果它们被修改了,那么测试签名就必须不同。因此,在数据没有改变的情况下,我们可以对用户进行身份验证。当然,如果这两个特征 是不同的,那就意味着有人篡改了数据。 通常是通过改变有效载荷。但是操纵有效载荷的第三方当然没有访问秘密的权限,所以他们不能签署JWT。 所以原始签名永远不会与被篡改的数据相对应。 因此,在这种情况下,验证总是失败的。这是整个系统运作的关键。正是这种魔力让智威汤逊如此简单,

Ref - JWT结构和安全性 . b

需要注意的是,JWT用于授权,而不是身份验证。 因此,只有在服务器通过指定凭据进行身份验证之后,才会为您创建JWT。一旦JWT为将来与服务器的所有交互创建了,就可以使用JWT了。因此,JWT告诉服务器该用户已通过身份验证,如果他拥有该角色,则允许他访问特定的资源。
JWT有效载荷中的信息对所有人都是可见的。可能会有一个“中间人”;攻击和JWT的内容可以改变。所以我们不应该在有效载荷中传递任何敏感信息,比如密码。我们可以加密有效载荷数据如果我们想让它更安全的话。如果有效载荷被篡改,服务器将识别它。
假设用户已经通过身份验证并提供了JWT。生成的JWT有一个声明,指定角色管理。此外,签名生成

enter image description here

这个JWT现在被篡改了,假设 角色更改为超级管理员
然后,当服务器接收到这个令牌时,它将再次使用秘密密钥(只有服务器拥有)和有效负载生成签名。与签名不符 在JWT。这样服务器就知道JWT被篡改了

我会用一个例子来解释。

假设我向你借了10美元,然后我给了你一张有我签名的借条。无论何时你或其他人把这张借条拿回来给我,我都会还你的,我会检查签名,确保那是我的。

我不能保证你不把这张借条的内容给任何人看,甚至给第三人看,我只关心这张借条是我签名的,当有人把这张借条给我看并让我支付的时候。

JWT的工作方式是完全相同的,服务器只能确保接收到的令牌是由自己发出的。

您需要其他措施来确保其安全,例如使用HTTPS传输时进行加密,确保存储令牌的本地存储是安全的,设置起源。