了解 JWT 的 RSA 签名
Understanding RSA signing for JWT
我正在 JWT(JSON Web 令牌)方案的帮助下实现登录系统。基本上,在用户登录/登录后,服务器签署一个 JWT 并将其传递给客户端。
客户端然后 returns 每个请求的令牌,服务器在发回响应之前验证令牌。
这与您的预期差不多,但我在流程逻辑上遇到了一些问题。从我读过的所有数学文章来看,RSA 签名似乎使用非对称密钥进行签名。 public 密钥,顾名思义,暴露给客户端并且私钥保存在服务器上,使用发送给客户端的 public 密钥签署 JWT 是有意义的并在服务器端使用私钥验证。
但是,在我看到的每个示例和库中,情况似乎都是相反的。知道为什么会这样吗?如果 JWT 使用私钥签名并使用 public 进行验证,那有什么意义呢?
您的建议:
it make sense to sign the JWT with the public key which is sent to the
client and verify it on the server side using the private key.
不正确。签名是使用发送方的私钥完成的,加密是使用接收方的 public 密钥完成的。这就是 PKI 通常的工作方式。
首先,抱歉,这个回答太长了。
如果您使用 RSA 对您的令牌进行签名,并且连接的客户端是网络浏览器,则客户端永远不会看到 RSA 密钥(public 或私有密钥)。这是因为客户端可能不需要验证 JWT 是否有效,只有服务器需要这样做。客户端只持有 JWT 并在服务器询问时将其显示给服务器。然后服务器检查以确保它在看到令牌时有效。
那么为什么您可能需要 JWT 的 public / 私钥组合?首先,您不需要使用 public / 私钥算法。
您可以使用多种不同的算法对 JWT 进行签名,RSA 就是其中之一。签署 JWT 的其他流行选择是 ECDSA 或 HMAC 算法(JWT 标准支持 others as well)。具体来说,HMAC 不是 public / 私钥方案。只有一个密钥,密钥,用于签署和验证令牌。您可以将其视为使用私钥对 JWT 进行签名和验证。无论如何我都不是这方面的专家,但这是我最近通过自己的研究得出的结论:
使用 HMAC 很好,因为它是最快的选择。但是,为了验证 JWT,您需要给某人一个可以执行所有操作的密钥,与其他人共享此密钥意味着该人现在也可以 sign 令牌并假装像他们一样是你如果您正在构建多个都需要能够验证您的 JWT 的服务器应用程序,您可能不希望每个应用程序都具有签署令牌的能力(不同的程序员可能会维护不同的应用程序,与更多人共享签名能力人员存在安全风险等)。在这种情况下,最好拥有一个严格控制的私钥(和一个执行签名的应用程序),然后与其他人共享 public 密钥,让他们能够验证令牌。这里,私钥用于对令牌进行签名,public 密钥用于验证它们。在这种情况下,您要选择 RSA 或 ECDSA。
As an example, you might have an ecosystem of apps that all connect to
the same database. To log users in, each app sends folks to one,
dedicated, 'logging in' app. This app has the private key. The other
apps can verify that the person is logged in using the public key (but
they can't log people in).
我所做的研究表明,在这种情况下,RSA 是大多数 JWT 应用程序的更好选择。这是因为从理论上讲,您的应用程序会经常验证令牌。 RSA 在验证方面比 ECDSA 快得多。 ECDSA 主要是因为密钥尺寸较小。这使得 HTTPS 证书更好,因为您需要将 public 密钥发送到客户端的浏览器。但在 JWT 场景中,密钥保留在服务器上,因此存储大小为 n/a,验证速度更重要。
结论:如果您正在构建一个没有多个较小的小型应用程序 'micro-service apps'/您是唯一的开发人员,可能会选择 HMAC 来加密您的密钥。否则,可能会选择 RSA。不过,我不是专家,只是最近在谷歌上搜索过这个主题的人,所以对此持保留态度。
signing/verifying 和 encrypting/decrypting 数据之间存在差异,但语义可能相似。
您使用只有受控来源拥有的私钥对数据进行签名,这样任何收到信息的人都可以使用您的 public 密钥来验证此信息确实是由您发送的,并且与您打算发送的信息相同出。
您使用 public 密钥加密数据并使用私钥解密。这听起来相反,但实际上遵循与签名相同的逻辑概念。如果你想在 A 和 B 之间发送数据,两个人都有一个 public/private 密钥对,并且他们在见面(握手)时彼此共享他们的 public 密钥。 A 为 B 构造一条消息并使用 B 的 public 密钥对其进行加密并将其发送给 B。现在,没有 B 的私钥的任何人都无法解密该消息,包括 A - 即使他们最初发送了它。
就 JWT 而言,JWT 有效载荷本身只是 Base64 编码 JSON 和一些标准化字段。签名允许拥有 public 密钥的人验证信息未被中间人更改。类似于校验和,但具有一些额外的基于安全性的温暖模糊感觉。已签名的 JWT 的内容对最终用户和中间的任何人来说都很容易看到(base64 编码类似于 unicode 或 utf-8,而不是加密),这就是为什么通常不赞成在 JWT 中发送敏感数据,如密码或PII.
正如其他人所提到的,大多数 JWT 包含的信息不是为客户准备的,而是为了帮助促进 RESTful 服务的无状态部分。通常,JWT 将包含一个帐户 ID、用户 ID 和通常作为“声明”的权限。 API 端点可以验证签名并合理地相信声明不会被客户端更改。让客户端为每个请求发送 JWT 可以节省端点来回执行大量数据库操作,只需使用 public 密钥验证签名即可到达它们所在的位置。
此外,签名的 JWT 可以加密。根据JWE spec,有效载荷在签名后加密,然后在验证前解密。这里的权衡是所有端点还必须具有私钥来解密 JWT,但最终用户将无法看到 JWT 的内容。我说权衡是因为通常私钥应该保持安全,而广泛分布的私钥安全性较低。安全性、风险评估和 cost/benefit 加密完全是另一回事 :)
我正在 JWT(JSON Web 令牌)方案的帮助下实现登录系统。基本上,在用户登录/登录后,服务器签署一个 JWT 并将其传递给客户端。
客户端然后 returns 每个请求的令牌,服务器在发回响应之前验证令牌。
这与您的预期差不多,但我在流程逻辑上遇到了一些问题。从我读过的所有数学文章来看,RSA 签名似乎使用非对称密钥进行签名。 public 密钥,顾名思义,暴露给客户端并且私钥保存在服务器上,使用发送给客户端的 public 密钥签署 JWT 是有意义的并在服务器端使用私钥验证。
但是,在我看到的每个示例和库中,情况似乎都是相反的。知道为什么会这样吗?如果 JWT 使用私钥签名并使用 public 进行验证,那有什么意义呢?
您的建议:
it make sense to sign the JWT with the public key which is sent to the client and verify it on the server side using the private key.
不正确。签名是使用发送方的私钥完成的,加密是使用接收方的 public 密钥完成的。这就是 PKI 通常的工作方式。
首先,抱歉,这个回答太长了。
如果您使用 RSA 对您的令牌进行签名,并且连接的客户端是网络浏览器,则客户端永远不会看到 RSA 密钥(public 或私有密钥)。这是因为客户端可能不需要验证 JWT 是否有效,只有服务器需要这样做。客户端只持有 JWT 并在服务器询问时将其显示给服务器。然后服务器检查以确保它在看到令牌时有效。
那么为什么您可能需要 JWT 的 public / 私钥组合?首先,您不需要使用 public / 私钥算法。
您可以使用多种不同的算法对 JWT 进行签名,RSA 就是其中之一。签署 JWT 的其他流行选择是 ECDSA 或 HMAC 算法(JWT 标准支持 others as well)。具体来说,HMAC 不是 public / 私钥方案。只有一个密钥,密钥,用于签署和验证令牌。您可以将其视为使用私钥对 JWT 进行签名和验证。无论如何我都不是这方面的专家,但这是我最近通过自己的研究得出的结论:
使用 HMAC 很好,因为它是最快的选择。但是,为了验证 JWT,您需要给某人一个可以执行所有操作的密钥,与其他人共享此密钥意味着该人现在也可以 sign 令牌并假装像他们一样是你如果您正在构建多个都需要能够验证您的 JWT 的服务器应用程序,您可能不希望每个应用程序都具有签署令牌的能力(不同的程序员可能会维护不同的应用程序,与更多人共享签名能力人员存在安全风险等)。在这种情况下,最好拥有一个严格控制的私钥(和一个执行签名的应用程序),然后与其他人共享 public 密钥,让他们能够验证令牌。这里,私钥用于对令牌进行签名,public 密钥用于验证它们。在这种情况下,您要选择 RSA 或 ECDSA。
As an example, you might have an ecosystem of apps that all connect to the same database. To log users in, each app sends folks to one, dedicated, 'logging in' app. This app has the private key. The other apps can verify that the person is logged in using the public key (but they can't log people in).
我所做的研究表明,在这种情况下,RSA 是大多数 JWT 应用程序的更好选择。这是因为从理论上讲,您的应用程序会经常验证令牌。 RSA 在验证方面比 ECDSA 快得多。 ECDSA 主要是因为密钥尺寸较小。这使得 HTTPS 证书更好,因为您需要将 public 密钥发送到客户端的浏览器。但在 JWT 场景中,密钥保留在服务器上,因此存储大小为 n/a,验证速度更重要。
结论:如果您正在构建一个没有多个较小的小型应用程序 'micro-service apps'/您是唯一的开发人员,可能会选择 HMAC 来加密您的密钥。否则,可能会选择 RSA。不过,我不是专家,只是最近在谷歌上搜索过这个主题的人,所以对此持保留态度。
signing/verifying 和 encrypting/decrypting 数据之间存在差异,但语义可能相似。
您使用只有受控来源拥有的私钥对数据进行签名,这样任何收到信息的人都可以使用您的 public 密钥来验证此信息确实是由您发送的,并且与您打算发送的信息相同出。
您使用 public 密钥加密数据并使用私钥解密。这听起来相反,但实际上遵循与签名相同的逻辑概念。如果你想在 A 和 B 之间发送数据,两个人都有一个 public/private 密钥对,并且他们在见面(握手)时彼此共享他们的 public 密钥。 A 为 B 构造一条消息并使用 B 的 public 密钥对其进行加密并将其发送给 B。现在,没有 B 的私钥的任何人都无法解密该消息,包括 A - 即使他们最初发送了它。
就 JWT 而言,JWT 有效载荷本身只是 Base64 编码 JSON 和一些标准化字段。签名允许拥有 public 密钥的人验证信息未被中间人更改。类似于校验和,但具有一些额外的基于安全性的温暖模糊感觉。已签名的 JWT 的内容对最终用户和中间的任何人来说都很容易看到(base64 编码类似于 unicode 或 utf-8,而不是加密),这就是为什么通常不赞成在 JWT 中发送敏感数据,如密码或PII.
正如其他人所提到的,大多数 JWT 包含的信息不是为客户准备的,而是为了帮助促进 RESTful 服务的无状态部分。通常,JWT 将包含一个帐户 ID、用户 ID 和通常作为“声明”的权限。 API 端点可以验证签名并合理地相信声明不会被客户端更改。让客户端为每个请求发送 JWT 可以节省端点来回执行大量数据库操作,只需使用 public 密钥验证签名即可到达它们所在的位置。
此外,签名的 JWT 可以加密。根据JWE spec,有效载荷在签名后加密,然后在验证前解密。这里的权衡是所有端点还必须具有私钥来解密 JWT,但最终用户将无法看到 JWT 的内容。我说权衡是因为通常私钥应该保持安全,而广泛分布的私钥安全性较低。安全性、风险评估和 cost/benefit 加密完全是另一回事 :)