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


302

如果获得JWT并且可以解码有效负载,那么这种安全性如何?我不能只是从标头中提取令牌,解码并更改有效负载中的用户信息,然后使用相同的正确编码机密将其发送回去吗?

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


1
md5('original messaged' + secret) != md5('changed message' + secret)因此,如果有人更改了邮件,您可以检测到它
Pithikos

在理想情况下为true,但是md5有冲突。@Pithikos
Yash Kumar Verma

@YashKumarVerma是的,这只是为了演示其要点,因为每个人都知道md5。
Pithikos

@Pithikos你怎么知道原始消息?
user1955934

1
@ user1955934它base64编码,NOT加密。您可以简单地使用任何base64解码器对其进行解码。
Pithikos

Answers:


386

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

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

假设Alice要向Bob发送JWT。他们俩都知道一些共同的秘密。马洛里不知道那个秘密,但是想干预和改变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}。您不能,因为您不知道我使用了哪个秘密。如果我认为收件人知道秘密,他可以计算任何邮件的签名并检查其是否正确。


8
那么当有效载荷改变时签名也改变了吗?我对令牌的印象是[header]。[payload]。[signature]格式是通过有效载荷和密钥的组合计算得出的签名吗?如果是这种情况,那么具有不同id的有效载荷会不会与该机密相同?就像数据是{id:1}并用于计算带有机密的令牌的签名部分一样,这并不意味着{id:2}对用户2有效,因此用户1可以更改id为2,令牌是否相同?
PixMach 2014年

7
我确实为您提供了一个示例,以使事情更加清晰,但是我不会向您解释整个数字签名和HMAC的概念。请仔细阅读这些内容,其中有很多材料对其进行解释。
Misch 2014年

11
哦,我现在明白了。我不知道为什么我丢失了这样的想法,即当您更改有效负载时,秘密哈希将是不正确的,因为必须重新计算秘密哈希。由于某种原因,我仍然认为它是独立的。最后一点对我来说真的很深刻。感谢您引导我完成此过程。
PixMach 2014年

30
我有一个相关的问题。是什么阻止某人通过复制的JWT模仿爱丽丝?
Morrowless

25
如果有人拥有JWT,则他们可以模仿Alice。因此,您需要注意如何存储和发送它。您还应该在有效负载中为其设置到期时间。这样,如果有人窃取了JWT,他们将有有限的时间使用它。看看stormpath.com/blog/...
杰兰特·安德森

134

您可以转到jwt.io,粘贴令牌并阅读内容。最初,这对很多人来说都是不愉快的。

简短的答案是,JWT本身与加密无关。它关心验证。也就是说,它总是可以得到“是否已操纵此令牌的内容”的答案?这意味着用户对JWT令牌的操作是徒劳的,因为服务器将知道并忽略该令牌。当向客户端颁发令牌时,服务器会基于有效负载添加签名。稍后,它会验证有效负载和匹配的签名。

逻辑上的问题是,不将自身与加密内容相关联的动机是什么?

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

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

  3. JWT并非旨在存储敏感数据。服务器接收到JWT令牌并对其进行验证后,便可以在其自己的数据库中查找用户ID,以获取该用户的其他信息(例如权限,邮政地址等)。这样可以使JWT保持较小的尺寸,并避免无意间泄漏信息,因为每个人都知道不要在JWT中保留敏感数据。

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


4
介意!JWT应该始终通过HTTPS之类的安全层进行交换
Codemirror

但是,如果JWT仅通过HTTPS是安全的,为什么不只发送有效载荷呢?POST->用户名,密码。还是加密的吧?
GeekPeek '19

对于@GeekPeek,您应该阅读JWT基础知识,但是像您提到的Session Auth通常就是您所需要的。智威汤逊提供了一些其他的好处,但提出了一些折中webskeleton.com/webdev/2019/10/22/...
aleemb

17

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

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

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

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


2

让我们从一开始就进行论述:

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

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

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

就像这样,对用户进行身份验证并基本上登录到我们的应用程序中,而无需在服务器上保留任何状态。

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

再次重申一下,只是为了确保您明白了。用户一旦取回其唯一的有效Json Web令牌(未保存在服务器上的任何位置),便立即登录。因此,此过程是完全无状态的。

然后,例如,每次用户想要访问受保护的路由(例如其用户配置文件数据)时。他将Json Web令牌与请求一起发送,因此有点像出示护照以访问该路由。

一旦请求到达服务器,我们的应用程序将验证Json Web令牌是否确实有效,并且如果用户确实是他说的真实身份,那么所请求的数据将被发送到客户端,如果没有,则将告诉用户不允许他访问该资源的错误。 在此处输入图片说明

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

在此处输入图片说明

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

因此,任何人都可以解码它们并读取它们,我们不能在此处存储任何敏感数据。但这根本不是问题,因为在签名的第三部分中,事情确实变得很有趣。使用标头,有效负载和服务器上保存的机密创建签名。

然后将整个过程称为对Json Web令牌进行签名。签名算法采用标头,有效负载和秘密来创建唯一的签名。因此,只有这些数据加上秘密才能创建此签名,好吗?然后,这些签名与标头和有效负载一起形成JWT,然后将其发送到客户端。 在此处输入图片说明

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

那么,此验证实际上如何工作?好吧,这实际上很简单。收到JWT后,验证将获取其标头和有效负载,以及仍保存在服务器上的机密信息,基本上会创建一个测试签名。

但是第一次创建JWT时生成的原始签名仍然在令牌中,对吗?这就是验证的关键。因为现在我们要做的就是将测试签名与原始签名进行比较。并且,如果测试签名与原始签名相同,则表示有效负载和标头尚未修改。 在此处输入图片说明

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


1

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

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


1
JWT并不总是加密的。可以对它们进行签名,加密,签名然后加密,或者加密然后签名。
csauve

0

对于像我这样负担不起昂贵数据库查询的人来说,一种保留敏感数据(用户权限等)的方法是,生成JWT时,您可以加密此数据并将其附加到JWT令牌。(将加密密钥保留在后端)

当您想读取敏感信息时,可以将JWT令牌发送到后端并对其解密,然后将其取回。这样,您不必进行数据库查找或通过JWT令牌将敏感信息裸露在前端


-1

我建议使用jwt.io中不存在的特殊算法解密JWE进行解密

参考链接:https : //www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

这个答案可能为时已晚,或者您可能已经找到了答案,但是我仍然认为这对您和其他人也有帮助。

我创建的一个简单示例:https : //github.com/hansiemithun/jwe-example

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.