了解JWT的RSA签名

时间:2016-07-26 11:12:31

标签: rsa jwt digital-signature

我在JWT(JsonWebToken)计划的帮助下实现了登录系统。基本上在用户登录/登录后,服务器签署JWT并将其传递给客户端。

然后客户端返回每个请求的令牌,服务器在发回响应之前验证令牌。

这几乎是你所期望的,但我对这个过程的逻辑有一些问题。从我读过的所有数学文章来看,似乎RSA签名使用非对称密钥进行签名。正如其名称所示,公钥暴露给客户端并且私钥保留在服务器上,使用发送到客户端的公钥对JWT进行签名并使用服务器端验证它是有意义的。私钥。

然而,在每个示例和库中我都看到它似乎是另一种方式,任何想法为什么它如此?如果JWT使用私钥签名并与公共密钥进行验证,那么该点是什么?

3 个答案:

答案 0 :(得分:33)

首先,道歉,这个答案变得相当长。

如果您使用RSA加密您的令牌,并且连接客户端是Web浏览器,则客户端将永远不会看到RSA密钥(公共或私有)。这是因为客户端可能不需要验证JWT是否有效,只有服务器需要这样做。客户端只需保留JWT并在询问时将其显示给服务器。然后服务器检查以确保它在看到令牌时有效。

那你为什么需要JWT的公钥/私钥组合呢?首先,您不需要使用公钥/私钥算法。

您可以使用多种不同的算法对JWT进行编码,RSA就是其中之一。编码JWT的其他流行选择是ECDSA或HMAC算法(JWT标准支持others as well)。具体而言,HMAC不是公钥/私钥方案。只有一个密钥密钥,用于加密和解密令牌。您可以将此视为使用私钥来签署和解密JWT。我无论如何都不是这方面的专家,但这是我最近从自己的研究中得出的结论:

使用HMAC很不错,因为它是最快的选择。但是,为了解密JWT,您需要为某人提供一键完成所有操作,与其他人共享此密钥意味着该人现在也可以签署令牌并假装他们就是您。如果您正在构建所有需要能够验证JWT的多个服务器应用程序,您可能也不希望每个应用程序都能够对令牌进行编码(不同的程序员可能会维护不同的应用程序,与更多的共享加密功能)人是安全隐患等)。在这种情况下,最好有一个严格控制的私钥(和一个执行签名的应用程序),然后与其他人共享公钥,使他们能够验证令牌。这里,私钥用于加密令牌,公钥用于解密它们。在这种情况下,您需要选择RSA或ECDSA。

  

例如,您可能拥有一个所有连接的应用程序生态系统   同一个数据库。要记录用户,每个应用程序将人们发送到一个,   专用,“登录”应用程序。这个应用程序有私钥。另一个   应用可以使用公钥验证此人是否已登录(但是   他们无法记录人员。

我所做的研究表明,在这种情况下,RSA是大多数JWT应用程序的更好选择。这是因为您的应用程序在理论上会经常验证令牌。在验证时,RSA比ECDSA快得多。 ECDSA主要是因为按键尺寸较小。这使得https证书更好,因为您需要将公钥发送到客户端的浏览器。但是在JWT方案中,密钥保留在服务器上,因此存储大小为n / a,验证速度更重要。

结论:如果您正在构建一个没有多个小型“微服务应用程序”的小应用程序/您是唯一的开发人员,可能会选择HMAC来加密您的密钥。否则,可能选择RSA。尽管如此,我不是专家,只是最近搜索过这个话题的人,所以请大家多说。

答案 1 :(得分:9)

你的建议:

  

用公钥发送给JWT是有意义的   客户端并使用私钥在服务器端验证它。

不正确。使用服务器的私钥进行签名,使用客户端的公钥进行加密。这就是PKI的一般工作方式。

答案 2 :(得分:2)

签名/验证与加密/解密之间存在区别,但是语义可以相似。

您使用只有受控来源拥有的私钥对数据进行签名,因此接收信息的任何人都可以使用您的公钥来验证此信息确实是您发送的,并且与您打算发送的信息相同。

您使用公用密钥加密数据,并使用专用密钥解密。这听起来相反,但实际上遵循与签名相同的逻辑概念。如果要在个人A和个人B之间发送数据,则两个人都有一个公钥/私钥对,并且他们在见面时(握手)彼此共享公钥。 A会为B构造一条消息,并使用B的公钥对其进行加密,然后将其发送给B。现在,没有B的私钥的任何人都无法解密包括A在内的该消息-即使他们最初发送了该消息。

就JWT而言,JWT有效负载本身只是具有某些标准化字段的Base64编码JSON。该签名允许具有公钥的人验证中间人是否未更改信息。类似于校验和,但具有一些额外的基于安全的温暖模糊感觉。最终用户和中间的任何人都可以轻松看到已签名的JWT的内容(base64的编码类似于unicode或utf-8,而不是加密),这就是为什么它通常不赞成在JWT中发送敏感数据(例如密码或密码)的原因。 PII

正如其他人提到的那样,大多数JWT包含的信息并非旨在提供给客户,而是用于帮助促进RESTful服务的无状态部分。通常,JWT将包含一个帐户ID,用户ID和通常的权限(称为“声明”)。 API端点可以验证签名,并合理地相信不会被客户端更改的声明。让客户端为每个请求发送JWT,可以节省端点仅通过使用公共密钥验证签名即可往返做很多数据库的工作。

此外,可以对签名的JWT进行加密。根据{{​​3}},有效载荷在签名后被加密,然后在验证之前被解密。这里要权衡的是,所有终结点计算机还必须具有私钥才能解密JWT,但最终用户将无法看到JWT的内容。我说要权衡一下,因为一般来说私钥应该保持安全,而广泛分布的私钥则不太安全。安全性,风险评估和加密的成本/收益是另一回事:)