【问题标题】:Understanding RSA signing for JWT了解 JWT 的 RSA 签名
【发布时间】:2016-11-30 00:13:55
【问题描述】:

我在 JWT(JSON Web Token)方案的帮助下实现了一个登录系统。基本上,在用户登录/登录后,服务器对 JWT 进行签名并将其传递给客户端。

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

这几乎是您所期望的,但我在流程的逻辑上遇到了一些问题。从我读过的所有数学文章中,似乎 RSA 签名使用非对称密钥进行签名。顾名思义,公钥向客户端公开,而私钥保存在服务器上,因此使用发送给客户端的公钥对 JWT 进行签名并在服务器端使用验证它是有意义的私钥。

但是,在我看到的每个示例和库中,情况似乎是相反的。知道为什么会这样吗?如果 JWT 使用私钥签名并使用公钥进行验证,那还有什么意义?

【问题讨论】:

    标签: rsa jwt digital-signature


    【解决方案1】:

    您的建议:

    使用发送到 客户端并使用私钥在服务器端进行验证。

    不正确。签名是使用发送者的私钥完成的,加密是使用接收者的公钥完成的。这就是 PKI 的一般工作方式。

    【讨论】:

    【解决方案2】:

    首先,抱歉,这个答案有点长。

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

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

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

    使用 HMAC 很好,因为它是最快的选择。但是,为了验证 JWT,您需要给某人一个可以做所有事情的密钥,与其他人共享此密钥意味着该人现在也可以 签署 令牌并假装他们是您.如果您正在构建多个都需要能够验证您的 JWT 的服务器应用程序,您可能不希望每个应用程序也都具有签名令牌的能力(不同的程序员可能正在维护不同的应用程序,与更多人共享签名能力人是安全风险等)。在这种情况下,最好拥有一个严格控制的私钥(以及一个执行签名的应用程序),然后与其他人共享公钥,让他们能够验证令牌。在这里,私钥用于签署令牌,而公钥用于验证它们。在这种情况下,您需要选择 RSA 或 ECDSA。

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

    我所做的研究表明,在这种情况下,对于大多数 JWT 应用来说,RSA 是更好的选择。这是因为从理论上讲,您的应用会频繁地验证令牌。 RSA 在验证方面比 ECDSA 快得多。 ECDSA 主要是因为密钥的大小更小。这使得 HTTPS 证书更好,因为您需要将公钥发送到客户端的浏览器。但在 JWT 场景中,密钥保留在服务器上,因此存储大小为 n/a,验证速度更为重要。

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

    【讨论】:

    • HMAC 是一种散列算法,不能用 HMAC 加密/解密。应该阅读stackoverflow.com/questions/4948322/… 以了解散列和加密之间的区别。
    • 我不认为这个答案解决了签名和加密之间的混淆,如问题中所述。
    • 我猜,问题是为什么大多数文章都说我们使用私钥来加密签名和公钥来验证提供的签名,而 RSA 密钥的使用方式相反。
    • 这个答案正是我想要的。谢谢!!!
    【解决方案3】:

    签名/验证和加密/解密数据之间存在差异,但语义可能相似。

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

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

    就 JWT 而言,JWT 有效负载本身就是带有一些标准化字段的 Base64 编码 JSON。签名允许拥有公钥的人验证信息未被中间人更改。类似于校验和,但具有一些基于额外安全性的温暖模糊感觉。签名的 JWT 的内容对最终用户和中间的任何人都很容易看到(base64 是像 unicode 或 utf-8 一样的编码,而不是加密),这就是为什么在 JWT 中发送敏感数据(如密码或PII.

    正如其他人所提到的,大多数 JWT 包含的信息并非针对客户端,而是帮助促进 RESTful 服务的无状态部分。通常,JWT 将包含一个 accountid、userid 和通常作为“声明”的权限。 API 端点可以验证签名并合理地相信声明不会被客户端更改。让客户端为每个请求发送 JWT,这样端点就不必来回执行大量数据库,只需使用公钥验证签名即可获得它们的位置。

    此外,签名的 JWT 可以加密。根据JWE spec,payload在签名后加密,然后在验证前解密。这里的权衡是所有端点还必须有私钥来解密 JWT,但最终用户将无法看到 JWT 的内容。我说权衡是因为通常私钥是为了保证安全,而广泛分布的私钥只是不那么安全。加密的安全性、风险评估和成本/收益完全是另一回事:)

    【讨论】:

      猜你喜欢
      • 2012-02-19
      • 2015-09-20
      • 2016-04-17
      • 2021-08-02
      • 2021-07-03
      • 2018-04-19
      • 2015-11-23
      • 2010-12-02
      • 1970-01-01
      相关资源
      最近更新 更多