我正在JWT (JSON Web Token)方案的帮助下实现一个登录系统。基本上,在用户登录/登录之后,服务器对JWT进行签名并将其传递给客户端。
然后,客户端为每个请求返回令牌,服务器在发回响应之前验证令牌。
这几乎是你所期望的,但我对这个过程的逻辑有一些问题。从我读过的所有数学文章来看,RSA签名似乎使用非对称密钥进行签名。顾名思义,公钥向客户端公开,私钥保存在服务器上,因此使用发送到客户端的公钥对JWT进行签名并使用私钥在服务器端对其进行验证是有意义的。
然而,在我看到的每个例子和库中,似乎都是相反的。你知道为什么会这样吗?如果一个JWT是用私钥签名的,并用公钥进行了验证,那还有什么意义呢?
发布于 2017-06-04 17:36:25
首先,很抱歉,这个答案太长了。
如果您使用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。再说一次,我不是专家,只是最近在谷歌上搜索过这个话题的人,所以对此持保留态度。
发布于 2016-07-26 19:17:53
你的建议:
使用发送到客户端的公钥对JWT进行签名,并使用私钥在服务器端验证它是有意义的。
是不正确的。签名是用发送方的私钥完成的,加密是用接收方的公钥完成的。这就是PKI通常的工作方式。
发布于 2018-08-19 04:17:41
签名/验证和加密/解密数据之间是有区别的,但语义可能是相似的。
您使用只有受控制来源才有的私钥对数据进行签名,以便接收该信息的任何人都可以使用您的公钥来验证此信息确实是由您发送的,并且与您打算发送的信息相同。
使用公钥加密数据,使用私钥解密数据。这听起来相反,但实际上遵循与签名相同的逻辑概念。如果你想在个人A和个人B之间发送数据,两个人都有一个公钥/私钥对,当他们见面(握手)时,他们彼此共享公钥。A为B构造一条消息,并使用B的公钥对其进行加密,然后将其发送给B。现在,没有B的私钥的任何人都无法解密包括A在内的消息--即使是他们最初发送的消息。
就JWT而言,JWT有效负载本身就是带有一些标准化字段的Base64编码的JSON。签名允许拥有公钥的人验证信息没有被中间人篡改。类似于校验和,但有一些额外的安全基于温暖模糊的感觉。最终用户和中间的任何人都可以很容易地看到签名的JWT的内容(base64的编码方式是unicode或utf-8,而不是加密),这就是为什么在JWT中发送密码或PII等敏感数据通常是不受欢迎的。
正如其他人所提到的,大多数JWT包含的信息不是为客户端设计的,而是为了帮助促进RESTful服务的无状态部分。通常,JWT将包含一个帐户an、用户an以及通常作为“声明”的权限。API端点可以验证签名并合理地信任声明不会被客户端更改。让客户端为每个请求发送JWT,这样端点就不必来回执行大量的数据库操作,只需简单地用公钥验证签名就可以得到它们所在的位置。
此外,签名的JWTs可以被加密。根据JWE spec,有效载荷在签名后加密,然后在验证之前解密。这里的权衡是,所有端点还必须拥有用于解密JWT的私钥,但最终用户将无法看到JWT的内容。我之所以说权衡,是因为一般来说,私钥应该是安全的,而广泛分布的私钥就不那么安全了。加密的安全性、风险评估和成本/收益完全是另一回事:)
https://stackoverflow.com/questions/38588319
复制相似问题