服务器如何验证 JWT? Public 密钥从何而来?
How does a server verify a JWT? Where does the Public Key come from?
我正在查看 Node.js 中 JWT 令牌的 examples,以及 verify
函数。我的问题是,这个 publicKey
从哪里来 verify(token, publicKey)
?流量是多少?
客户端(我的一个用户)在其 computer/server 上安装了客户端库,用于向我的应用程序发出请求 myapp.com
。在 myapp.com
服务器中,我调用 verify(token, publicKey)
。在客户端库中,我使用 privateKey
生成令牌。问题是,客户端一般是怎么得到这个私钥的呢? (即 heroku login
是在幕后下载私钥以发出 JWT 请求之类的吗?)。以及如何获取 public 键?我的理解是,客户端会下载私钥,而我们的服务器会存储 public 密钥。然后假设您有 public 密钥和令牌,只需调用 verify(token, publicKey)
。但是一般服务器上的token的public键是怎么得到的呢?服务器是否为每个分发给客户端安装的库的私钥存储一个 public 密钥?
我平时看到的JWTs的使用方式,只有极少数的可信发行者,通常只有一个,并且令牌被用作不记名令牌。在很多情况下,发行者和验证者是同一个人。在其他情况下,验证者信任一个身份提供者(例如 Google)并从 https URL (example).
中获取 public 密钥。
在您的情况下,您可以同时充当发行人和验证人:
- 你(服务器)会生成一个密钥对。
- 您的 API 服务器将信任由此密钥签名的 JWT(并且他们只有 public 密钥,因为他们只需要验证它们)。
- authentication/management 服务器将拥有 私有 密钥,将对您的用户进行身份验证,并向他们颁发 JWT。
- 客户端永远不会处理任何密钥,他们只会存储签名的 JWT,并在发出客户端请求时将其作为不记名令牌传递。
例如该方法将 here 描述为 GitHub 使用的方法。在这种情况下,发行人和验证人都属于你。这种方法对您(验证签名后可以信任 JWT 的内容)和客户端(他们只是处理不透明的 API 密钥,不需要完全处理 JWT 的复杂性)。
一种可能的替代方法是:
- 生成密钥对,public密钥与帐户相关联。这可以通过多种方式完成(见下文),但最终结果是相同的:客户端有一个私钥,你的服务器知道相应的 public 密钥 以及它关联的用户与
- 发出请求时,客户端会创建一个 JWT,使用其私钥对其进行签名,然后在令牌中包含他们的用户名(例如在
iss
和或 sub
字段)。
- 您的服务器获取令牌,提取用户名,在数据库中查找与帐户关联的 public 密钥,并验证令牌。
例如使用这种方法通过 Google 云 for service account authentication.
上面的第 1 步可以通过两种方式完成:
- 您对用户进行身份验证,生成密钥对,将 public 密钥与帐户相关联,然后让用户下载他们的私钥(当然是通过 https)。虽然为其他人生成密钥通常被认为是一种不好的形式(因为你会看到一个你不需要知道的密钥并且你必须通过网络发送它),但它更容易,并且 Google 就是这样做的。
- 用户生成并存储密钥对。您对用户进行身份验证,用户上传 public 密钥,您将其与帐户相关联。
无论哪种方式,如果您采用“用户签署 JWT”方法,您可能需要提供客户端库,或者至少提供代码示例。另请注意 Google 的要求,即令牌必须是短期的,通过将长期存在的令牌视为无效来强制执行。如果没有这条规则和执行,将会发生的是,许多客户端开发人员会对您复杂的解决方案感到恼火,手动签署一个永久有效的令牌在他的笔记本电脑上,然后将其用作不记名令牌。
heroku login
实际上根本不使用 JWT。它 retrieves and stores 一个 OAuth Bearer Token。这与第一种方法最相似(客户端从不处理任何私钥,只是得到一个不透明的 blob,它恰好是一个你可以验证的 JWT)。非 JWT 令牌和长期 JWT 之间的区别在于,您的 API 服务器必须在数据库中查找常规令牌的含义和有效性,而 JWT 直接告诉您用户身份,并且可能是您在发布时包含的权限和其他属性。
我正在查看 Node.js 中 JWT 令牌的 examples,以及 verify
函数。我的问题是,这个 publicKey
从哪里来 verify(token, publicKey)
?流量是多少?
客户端(我的一个用户)在其 computer/server 上安装了客户端库,用于向我的应用程序发出请求 myapp.com
。在 myapp.com
服务器中,我调用 verify(token, publicKey)
。在客户端库中,我使用 privateKey
生成令牌。问题是,客户端一般是怎么得到这个私钥的呢? (即 heroku login
是在幕后下载私钥以发出 JWT 请求之类的吗?)。以及如何获取 public 键?我的理解是,客户端会下载私钥,而我们的服务器会存储 public 密钥。然后假设您有 public 密钥和令牌,只需调用 verify(token, publicKey)
。但是一般服务器上的token的public键是怎么得到的呢?服务器是否为每个分发给客户端安装的库的私钥存储一个 public 密钥?
我平时看到的JWTs的使用方式,只有极少数的可信发行者,通常只有一个,并且令牌被用作不记名令牌。在很多情况下,发行者和验证者是同一个人。在其他情况下,验证者信任一个身份提供者(例如 Google)并从 https URL (example).
中获取 public 密钥。在您的情况下,您可以同时充当发行人和验证人:
- 你(服务器)会生成一个密钥对。
- 您的 API 服务器将信任由此密钥签名的 JWT(并且他们只有 public 密钥,因为他们只需要验证它们)。
- authentication/management 服务器将拥有 私有 密钥,将对您的用户进行身份验证,并向他们颁发 JWT。
- 客户端永远不会处理任何密钥,他们只会存储签名的 JWT,并在发出客户端请求时将其作为不记名令牌传递。
例如该方法将 here 描述为 GitHub 使用的方法。在这种情况下,发行人和验证人都属于你。这种方法对您(验证签名后可以信任 JWT 的内容)和客户端(他们只是处理不透明的 API 密钥,不需要完全处理 JWT 的复杂性)。
一种可能的替代方法是:
- 生成密钥对,public密钥与帐户相关联。这可以通过多种方式完成(见下文),但最终结果是相同的:客户端有一个私钥,你的服务器知道相应的 public 密钥 以及它关联的用户与
- 发出请求时,客户端会创建一个 JWT,使用其私钥对其进行签名,然后在令牌中包含他们的用户名(例如在
iss
和或sub
字段)。 - 您的服务器获取令牌,提取用户名,在数据库中查找与帐户关联的 public 密钥,并验证令牌。
例如使用这种方法通过 Google 云 for service account authentication.
上面的第 1 步可以通过两种方式完成:
- 您对用户进行身份验证,生成密钥对,将 public 密钥与帐户相关联,然后让用户下载他们的私钥(当然是通过 https)。虽然为其他人生成密钥通常被认为是一种不好的形式(因为你会看到一个你不需要知道的密钥并且你必须通过网络发送它),但它更容易,并且 Google 就是这样做的。
- 用户生成并存储密钥对。您对用户进行身份验证,用户上传 public 密钥,您将其与帐户相关联。
无论哪种方式,如果您采用“用户签署 JWT”方法,您可能需要提供客户端库,或者至少提供代码示例。另请注意 Google 的要求,即令牌必须是短期的,通过将长期存在的令牌视为无效来强制执行。如果没有这条规则和执行,将会发生的是,许多客户端开发人员会对您复杂的解决方案感到恼火,手动签署一个永久有效的令牌在他的笔记本电脑上,然后将其用作不记名令牌。
heroku login
实际上根本不使用 JWT。它 retrieves and stores 一个 OAuth Bearer Token。这与第一种方法最相似(客户端从不处理任何私钥,只是得到一个不透明的 blob,它恰好是一个你可以验证的 JWT)。非 JWT 令牌和长期 JWT 之间的区别在于,您的 API 服务器必须在数据库中查找常规令牌的含义和有效性,而 JWT 直接告诉您用户身份,并且可能是您在发布时包含的权限和其他属性。