服务器如何验证 JWT?公钥从哪里来?

Lan*_*ard 5 security public-key-encryption jwt

我正在查看Node.js 中 JWT 令牌的示例以及该verify函数。我的问题是,这是从哪里来publicKeyverify(token, publicKey)?什么是流量?

客户端(我的用户之一)在其计算机/服务器上安装了一个客户端库,用于向我的应用程序发出请求myapp.com。在myapp.com服务器中,我调用verify(token, publicKey). 在客户端库中,我使用 生成令牌privateKey。问题是,客户端一般如何获取这个私钥呢?(即heroku login在后台下载私钥以发出 JWT 请求之类的事情?)。如何获取公钥?我的理解是,客户端将下载私钥,我们的服务器将存储公钥。然后,如果您拥有公钥和令牌,只需调用verify(token, publicKey). 但是一般如何获取服务器上令牌的公钥呢?服务器是否为每个私钥存储一个公钥并传播到客户端安装的库?

Jan*_*bal 6

我通常看到 JWT 的使用方式是,只有极少数可信发行者,通常只有一个,并且令牌被用作不记名令牌。在许多情况下,发行者和验证者是相同的。在其他情况下,验证者信任一个身份提供商(例如 Google)并从 https URL 获取公钥(示例)。

就您而言,您可以同时充当发行者和验证者:

  1. (服务器)将生成对密钥。
  2. 您的 API 服务器将信任由此密钥签名的 JWT(并且它们只有公钥,因为它们只需要验证它们)。
  3. 身份验证/管理服务器将拥有私钥对您的用户进行身份验证,并向他们颁发 JWT。
  4. 客户端永远不会处理任何密钥,它们只是存储签名的 JWT,并在发出客户端请求时将其作为不记名令牌传递。

例如,这就是此处描述的GitHub 使用的方法。在这种情况下,发行者和验证者都属于您。这种方法对于您(验证签名后您可以信任 JWT 的内容)和客户端(他们只是处理不透明的 API 密钥,不需要处理复杂性)来说都是最简单的JWT 的总数)。


一种可能的替代方法可能是:

  1. 生成密钥对并将公钥与帐户关联。这可以通过多种方式完成(见下文),但最终结果是相同的:客户端有一个私钥,并且您的服务器知道相应的公钥以及它与哪个用户关联
  2. 发出请求时,客户端创建 JWT,使用其私钥对其进行签名,并将其用户名包含在令牌中(例如在issand 或sub字段中)。
  3. 您的服务器获取令牌,提取用户名,在数据库中查找与该帐户关联的公钥,然后验证令牌。

例如,Google Cloud 使用此方法进行服务帐户身份验证

上述步骤 1 可以通过两种方式完成:

  • 您对用户进行身份验证,生成密钥对,将公钥与帐户关联,然后让用户下载其私钥(当然是通过 https)。虽然为其他人生成密钥通常被认为是一种不好的形式(因为你会看到一个你不需要知道的密钥,并且你必须通过网络发送它),但它要容易得多,谷歌正在做的只是这。
  • 用户生成并存储密钥对。您对用户进行身份验证,用户上传公钥,然后将其与帐户关联。

无论哪种方式,如果您采用“用户签署 JWT”方法,您可能会想要提供客户端库,或者至少是代码示例。另请注意,Google 要求令牌必须是短期的,通过将长期令牌视为无效来强制执行。如果没有这个规则和执行将会发生的情况是,许多客户端开发人员会对您复杂的解决方案感到恼火,手动签署在他的笔记本电脑上永远有效的令牌,然后将其用作不记名令牌。


heroku login实际上根本不使用 JWT。它检索并存储OAuth 承载令牌。这与第一种方法最相似(客户端从不处理任何私钥,只是获取一个不透明的 blob,它恰好是您可以验证的 JWT)。非 JWT 令牌和长期 JWT 之间的区别在于,您的 API 服务器必须在数据库中查找常规令牌的含义和有效性,而 JWT 直接告诉您用户身份,以及可能的权限和其他信息您在发布时包含的属性。