ChatGPT解决这个技术问题 Extra ChatGPT

如果您可以解码 JWT,它们的安全性如何?

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

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

md5('original messaged' + secret) != md5('changed message' + secret) 因此,如果有人更改了消息,您可以检测到它
@YashKumarVerma 是的,这只是为了展示它的要点,因为每个人都知道 md5。
@user1955934 它是 base64 编码的,未加密。您可以简单地使用任何 base64 解码器对其进行解码。
所以客户端需要同时发送哈希和 jwt 令牌?稍后在服务器端,他们将尝试使用秘密对 jwt 令牌进行哈希处理并与哈希值进行比较?
服务器永远不应该信任客户端来处理和返回敏感数据。只有服务器可以在内部使用的哈希值来检索实际数据,很可能来自数据库。

H
HDJEMAI

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。现在轮到你了:扮演 Mallory 的角色并尝试在消息 {"id":2} 上签名。你不能,因为你不知道我使用了哪个秘密。如果我假设接收者知道这个秘密,他可以计算任何消息的签名并检查它是否正确。


那么当payload改变时,签名也会改变?我的印象是令牌的格式为 [header].[payload].[signature] 是由有效负载和秘密组合计算的签名吗?如果是这种情况,那么具有不同 id 的有效负载是否与该秘密相同?就像数据是 { id:1 } 并且用于计算带有秘密的令牌的签名部分,这是否意味着 { id:2 } 对用户 2 有效,因此用户 1 可以更改id 为 2 和令牌会是一样的吗?
哦,我现在明白了。我不知道为什么我错过了当您更改有效负载时秘密散列不正确的想法,因为必须重新计算秘密散列。出于某种原因,我仍然认为它是独立的。最后一点真的把它钻回家了。感谢您引导我完成它。
我有一个相关的问题。是什么阻止某人使用复制的 JWT 冒充 Alice?
如果有人拥有 JWT,他们可以冒充 Alice。所以你需要小心你如何存储和发送它。您还应该在有效负载中为其设置过期时间。这样,如果有人窃取了 JWT,他们使用它的时间是有限的。看看stormpath.com/blog/…
@Morrowless 我遇到了用户“共享”令牌的问题。我们为提高安全性所做的就是使用用户的 IP 地址作为解密过程的一部分。因为这发生在后端;用户可以与另一个用户共享令牌,但不知道为什么会被拒绝。同时,我们销毁/使共享令牌无效,因此两个用户都必须再次登录并获得新令牌。当然,这并不完美,因为如果您连接到同一个网络,您仍然可以摆脱它。我希望看到的是通过标头传递的浏览器强制会话 ID。
g
gunr2171

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

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

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

最简单的原因是因为它假设这在很大程度上是一个已解决的问题。例如,如果与 Web 浏览器之类的客户端打交道,您可以将 JWT 令牌存储在安全的 cookie 中(不通过 HTTP 传输,仅通过 HTTPS)和 httpOnly(无法被 Javascript 读取)并与服务器通过加密通道 (HTTPS)。一旦你知道你在服务器和客户端之间有一个安全通道,你就可以安全地交换 JWT 或任何你想要的东西。这让事情变得简单。一个简单的实现使采用更容易,但它也让每一层都做它最擅长的事情(让 HTTPS 处理加密)。 JWT 并不意味着存储敏感数据。一旦服务器接收到 JWT 令牌并对其进行验证,它就可以在自己的数据库中查找用户 ID 以获取该用户的其他信息(如权限、邮政地址等)。这使得 JWT 体积小,并且避免了不经意的信息泄露,因为每个人都知道不要将敏感数据保存在 JWT 中。

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


介意它! JWT 应始终通过 HTTPS 等安全层进行交换
但是,如果 JWT 仅通过 HTTPS 是安全的,为什么不直接发送有效负载呢? POST -> 用户名、密码。它仍然是加密的吗?
@GeekPeek 为此,您应该阅读 JWT 基础知识,但是您提到的 Session Auth 通常是您所需要的。 JWT 提供了一些其他好处,但也做了一些权衡webskeleton.com/webdev/2019/10/22/…
您只是阅读了我的想法,实际上,由于我是新手,我很惊讶 jwt.io 可以读取我的有效负载,那么签名到底在做什么?现在我最大的问题是如果你的 JWT 被盗了怎么办?!!!
密码、信用卡详细信息等敏感信息不得在 JWT 中编码
A
Arthur Costa

让我们从头开始讨论:

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

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

https://i.stack.imgur.com/UXiHK.png

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

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

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

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

https://i.stack.imgur.com/tTxqp.png

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

https://i.stack.imgur.com/0FpIC.png

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

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

https://i.stack.imgur.com/bOHqZ.png

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

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

https://i.stack.imgur.com/b2dzI.png

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


嗨@Lord,这太棒了!我不知道为什么它的票数这么少!
嗨@ani0904071,在下面的链接中你会找到一个node.js的例子,我希望它也会有所帮助。 stackoverflow.com/questions/31309759/…
这个答案太棒了!在非常简化的形式中,如果 JWT 是“2.5.9”(header=2,payload=5,signature=9),那么篡改它并将数据更改为 6 将不起作用。假设服务器的秘密乘以 header*payload 并减去 1。“测试签名”将是 2*6-1=11。但是 JWT 的签名是 9,所以服务器知道有东西被篡改了。理解起来很容易,但由于某些原因,许多文章忽略了低级的东西,这使它看起来比实际更神奇和复杂。
谢谢,现在我明白了。如此简单,却又如此难以掌握。现在看来是微不足道的。
问题不在于修改 JWT 时会发生什么。问题是当 B 可以访问 A 的 JWT 时会发生什么(例如,他们坐在一起,A 去厕所,B 在 A 的 chrome 中打开开发工具并从本地存储复制粘贴 JWT 并发送它到他的电脑),并使用它在 API 中发出调用。如何判断来自 B 个人电脑(但实际上是发给 A)的请求是无效的?
T
ThisClark

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

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

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

更多阅读:How does a public key verify a signature?


S
Sheng Zhuang

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

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

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

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

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


完美的比喻!
> 使用 HTTPS 传输加密,确保存储令牌的本地存储是安全的,设置来源 < 请更详细地解释如何做到这一点?
B
Batman Rises

Ref - JWT Structure and Security

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

https://i.stack.imgur.com/IIsJ3.png

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


+1 强调 JWT 不是用于 authn,而是用于 authz。我不知道为什么这么多网站和人们说他们是为了 authn。 JWT 根本不证明请求者的身份。我想每个人都试图推断请求者在他们对您的服务进行身份验证后才会有 JWT,但这不一定是真的。
只是好奇.. @Ungeheuer 为什么您认为 JWT 不被视为 authentication 令牌?它具有存在用户信息的有效负载。 headerpayloadsecret key 用于“验证”原始签名(最初由身份验证服务器生成),这意味着如果有效负载发生任何变化,则称用户不是原始用户,因此不是是不是简化了身份验证过程,即使用令牌我们可以对每个请求的用户进行身份验证,而无需再次访问身份验证服务器,然后允许基于用户角色访问资源。
cloud.google.com/api-gateway/docs/authenticating-users-jwt 以其他方式解释了此答案的解释。
s
sdfdsf sdf

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

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


JWT 并不总是加密的。它们可以被签名、加密、签名然后加密或加密然后签名。