是否可以在没有密钥的情况下验证 JWT 令牌?

Isa*_*122 2 authentication jwt next.js

最近在学习JWT。
我计划在 Next.js 服务器上采用 JWT,并使用发出 JWT 访问令牌的外部身份验证服务器。

起初我在考虑以下逻辑(当影响数据时)

  1. 用户使用 JWT 访问令牌发送请求
  2. 某个外部服务器收到该请求
  3. 将 JWT 访问令牌发送到颁发 JWT 令牌的身份验证服务器以进行验证
  4. 某个外部服务器根据验证结果做出响应
  5. 用户得到响应

但我认为这是非常低效的。

然后我看到一篇博客文章说:
“JWT 比其他基于令牌的身份验证解决方案更好,因为它不会向身份验证服务器发出进一步的验证请求,而是微服务本身验证令牌的有效性”

但是没有密钥就不可能验证 JWT 令牌吗?
如果是这样,在许多不同的微服务中存储 JWT 密钥是否安全?(我使用 dotenv 来存储密钥)

Dai*_*Dai 6

最近在学习JWT。我计划在 Next.js 服务器上采用 JWT,并使用发出 JWT 访问令牌的外部身份验证服务器。起初我在考虑以下逻辑(当影响数据时)

我想起了这句话“当你唯一的工具是锤子时...... ”。

(为了清楚起见,我通过添加 OAuth/OIDC 规范中的常用术语来调整您的事件序列)

  1. 客户端使用 JWT 访问令牌发送请求(并等待 RP 的响应)。
  2. 某个外部服务器(RP)接收该请求
  3. RP 将 JWT 访问令牌发送到颁发 JWT 令牌的身份验证服务器 (IdP) 进行验证
  4. RP根据步骤3中IdP的响应拒绝或接受客户端的请求,并完成步骤1中客户端的请求。

但我认为这是非常低效的。

没错,就是效率低下。

  • 您所描述的是RP 和 IdP 之间存在反向通道通信。

    • 通常不需要使用反向通道,因为它首先违背了使用分布式 authX 方案的目的(因为它要求反向通道可靠,否则 RP 无法工作,并且总体而言它会阻碍 RP系统独立运行)。
    • 通常,IdP、客户端和 RP 之间的所有通信都是通过“前通道”完成的,即客户端负责在 IdP 和 RP 之间传递消息(通常以 HTTP 中的 Cookie 和承载令牌的形式)要求)。
  • 作为括号:请注意,JWT 通常不会加密,因为JWT 中的任何声明本身都不应该是“秘密”值(但如果绝对需要,您可以加密 JWT );另请注意,如果您不是 IdP,则您无法控制此情况;另请注意,某些方案和系统可能要求 JWT 未加密,但这是另一个问题)。

  • 关于 JWT 签名的一些背景故事:

    • RP 需要能够知道它可以信任来自 IdP 的 JWT 中的声明:这是通过让 IdP 对 JWT 进行加密签名并确保 RP 可以以某种方式验证该签名来确保的。

    • 然后 RP 可以通过以下任一方式验证签名:

      1. 已经拥有本地运行签名验证算法所需的密钥。
      2. 将验证委托回 IdP。
    • 在运行良好的分布式系统中,系统之间的依赖性应该最小,因此第二个选项(将验证委托给 IdP)是不可取的,因此我们应该更喜欢第一个选项 - 并且第一个选项不需要使用对称密钥(必须保密)。

然后我看到一篇博客文章说“ JWT 比其他基于令牌的身份验证解决方案更好,因为它不会向身份验证服务器发出进一步的验证请求,而是微服务本身验证令牌的有效性

事实实际上要复杂得多:您读到的文章是一个不幸的例子,有人将广泛和具体的术语混合在一起并得出不准确(且不完整)的结论(特别是暗示 JWT 是唯一支持分布式非对称的方案)加密签名,因为它不是)。

但是没有密钥就不可能验证 JWT 令牌吗?如果是这样,在许多不同的微服务中存储 JWT 密钥是否安全?(我使用 dotenv 来存储密钥)

不,您需要了解非对称加密在这种情况下是如何工作的;但首先,请记住 JWT 可以使用许多不同类型的技术进行签名,而不仅仅是非对称加密签名。

为简单起见,请遵循以下流程图:

  1. RP 收到未加密但已签名的 JWT。JWT 中的(发行者iss,IdP)和aud(受众,RP)声明正确对应于 IdP 和 RP。
  2. 如果 JWT 使用非对称算法(例如RS256ES256)进行签名,则意味着 JWT 是使用 IdP 的(秘密)私钥进行签名的并且可以使用RP 需要能够访问的IdP 的公钥来验证签名。
    1. RP应该已经在本地缓存了 IdP 的公钥:如果 RP 收到用密钥签名的 JWT,那么它没有公钥,那么是的:RP 将需要直接联系 IdP 并缓存它(这是由总体方案定义的,例如 OIDC,它要求 IdP 在 公开其公钥https://{authority}/.well-known/openid-configuration)。
    2. 然后,RP 使用 IdP 的公钥来验证 JWT 上的签名,并验证nbf(之前无效)和exp(过期)声明,以及任何其他最低限度必要的声明。
      • 签名验证不需要 IdP 的任何通信或参与,除了检索公钥之外,这应该只需要发生一次(并且为了简单起见,检索公钥的行为可以在 RP 的服务器启动序列期间发生)或者在系统部署/配置期间(例如,这对于气隙网络是必需的),因此当 RP 收到基于 JWT 的请求时,这种情况永远不会发生。
  3. 如果 JWT 使用对称(非非对称)算法(例如HS256)进行签名,则有两种方法可以继续:
    • (请注意,对称签名的 JWT 是一个坏主意:它允许 RP 也创建自己的 JWT,这意味着 IdP 需要信任 RP 不会滥用其密钥,但分布式系统中的规则 #1 是不信任任何人。)
    1. 选项 1:IdP 和 RP * 都需要在其本地密钥缓存中拥有对称(秘密)私钥。与非对称密钥一样,RP 可以通过反向通道按需从 IdP 获取此密钥,也可以在 RP 部署或启动过程中预共享并提供给 RP。
    2. 选项 2:如果无法通过对称私钥信任 RP,则 RP 需要向 IdP 发出反向通道请求,将整个 JWT 传回 IdP 进行验证(IdP 将使用简单的“是”进行响应) /no":因为 RP 仍然可以使用 JWT 中的声明,因为它们未加密)。
      • 当然,RP可以缓存 IdP 的是/否响应(基于 JWT 的某些独特特征,例如其哈希值或令牌 ID),以避免必须为每个JWT向 IdP 发出反向通道请求。基于客户提出的请求。