473

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

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

4

7 回答 7

567

JWT 可以是签名的、加密的或两者兼有。如果一个令牌是签名的,但没有加密,每个人都可以读取它的内容,但是当你不知道私钥时,你就无法更改它。否则,接收者会注意到签名不再匹配。

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

假设 Alice 想向 Bob 发送一个 JWT。他们都知道一些共同的秘密。马洛里不知道这个秘密,但想干预和改变智威汤逊。为了防止这种情况发生,Alice 计算Hash(payload + secret)并将其附加为签名。

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

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

于 2014-12-04T18:45:38.637 回答
207

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

简短的回答是 JWT 不关心加密。它关心验证。也就是说,它总能得到“这个令牌的内容是否被操纵”的答案?这意味着用户对 JWT 令牌的操作是徒劳的,因为服务器会知道并忽略令牌。服务器在向客户端发出令牌时,会根据有效负载添加签名。稍后它会验证有效负载和匹配的签名。

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

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

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

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

这与 cookie 本身的工作方式并没有太大的不同。Cookie 通常包含未加密的有效负载。如果您使用的是 HTTPS,那么一切都很好。如果您不是,那么建议您自己加密敏感的 cookie。不这样做将意味着中间人攻击是可能的——代理服务器或 ISP 读取 cookie,然后在稍后假装是您时重放它们。出于类似的原因,JWT 应始终通过 HTTPS 等安全层进行交换。

于 2017-02-22T09:24:29.417 回答
170

让我们从头开始讨论:

JWT 是一种非常现代、简单且安全的方法,可扩展为 Json Web Tokens。Json Web Tokens 是一种用于身份验证的无状态解决方案。所以不需要在服务器上存储任何会话状态,这对于 RESTful API 来说当然是完美的。Restful API 应该始终是无状态的,使用 JWT 进行身份验证的最广泛使用的替代方法是使用会话将用户的登录状态存储在服务器上。但是当然没有遵循 RESTful API 应该是无状态的原则,这就是 JWT 之类的解决方案变得流行和有效的原因。

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

令牌是使用存储在服务器上的秘密字符串创建的。接下来,服务器将该 JWT 发送回客户端,客户端会将其存储在 cookie 或本地存储中。 在此处输入图像描述

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

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

再说一次,只是为了确保你明白了。用户在取回其唯一的有效 Json Web 令牌后立即登录,该令牌未保存在服务器上的任何位置。因此,这个过程是完全无状态的。

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

一旦请求到达服务器,我们的应用程序将验证 Json Web Token 是否真的有效,如果用户真的是他所说的那个人,那么请求的数据将被发送到客户端,如果不是,那么将会是一个错误,告诉用户他不允许访问该资源。 在此处输入图像描述

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

在此处输入图像描述

因此,Json Web Token 看起来像此屏幕截图的左侧部分,该屏幕截图取自 jwt.io 的 JWT 调试器。所以本质上,它是一个由三部分组成的编码字符串。标头、有效负载和签名 现在标头只是关于令牌本身的一些元数据,有效负载是我们可以编码到令牌中的数据,是我们真正想要的任何数据。所以我们想要在这里编码的数据越多,JWT 就越大。无论如何,这两个部分只是将被编码但未加密的纯文本。

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

然后将整个过程称为签署 Json Web Token。签名算法采用标头、有效负载和秘密来创建唯一签名。所以只有这个数据加上秘密才能创建这个签名,好吗?然后与标头和有效负载一起,这些签名形成 JWT,然后发送到客户端。 在此处输入图像描述

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

那么,这种验证实际上是如何工作的呢?嗯,它实际上很简单。收到 JWT 后,验证将获取其标头和有效负载,并与仍保存在服务器上的秘密一起,基本上创建一个测试签名。

但是最初创建 JWT 时生成的原始签名仍在令牌中,对吧?这就是验证的关键。因为现在我们要做的就是将测试签名与原始签名进行比较。而如果测试签名与原始签名相同,则说明payload和header没有被修改。 在此处输入图像描述

因为如果它们已被修改,那么测试签名将必须不同。因此,在这种数据没有更改的情况下,我们可以对用户进行身份验证。当然,如果这两个签名实际上不同,那么这意味着有人篡改了数据。通常通过尝试更改有效负载。但是操纵有效载荷的第三方当然无法访问机密,因此他们无法签署 JWT。所以原始签名永远不会对应于被操纵的数据。因此,在这种情况下,验证总是会失败。这是使整个系统正常工作的关键。正是这种魔力让 JWT 变得如此简单,但也非常强大。

于 2020-05-29T21:46:07.270 回答
29

json Web 令牌 (JWT) 中的内容本质上并不安全,但有一个用于验证令牌真实性的内置功能。JWT 是由句点分隔的三个哈希值。三是签名。在公钥/私钥系统中,发行者使用私钥对令牌签名进行签名,私钥只能通过其相应的公钥进行验证。

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

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

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

于 2017-04-19T13:53:36.583 回答
17

我会用一个例子来解释这一点。

假设我向你借了 10 美元,然后我给了你一张带有我签名的借据。每当您或其他人将这张借条带回给我时,我都会还给您,我会检查签名以确保那是我的。

我不能确保你不把这张借条的内容给任何人,甚至给第三人,我只关心这张借条是我签名的,当有人给我看这张借条并要求我付钱。

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

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

于 2021-03-05T11:59:08.973 回答
6

参考 - JWT 结构和安全性

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

在此处输入图像描述

此 JWT 现在已被篡改,假设角色更改为超级管理员
,那么当服务器收到此令牌时,它将再次使用密钥(只有服务器拥有)和有效负载生成签名。它与 JWT 中的签名不匹配。这样服务器就会知道 JWT 被篡改了。

于 2020-08-06T19:22:18.383 回答
1

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

将私钥隐藏在服务器的安全位置,切勿将私钥告诉任何人。

于 2017-11-14T01:40:39.380 回答