Spring Cloud Security JWT:使用配置服务器/密钥轮换分发公钥

Posted

技术标签:

【中文标题】Spring Cloud Security JWT:使用配置服务器/密钥轮换分发公钥【英文标题】:Spring Cloud Security JWT: Distribute Public Key using Config Server / Key Rotation 【发布时间】:2019-01-27 13:35:58 【问题描述】:

如何在 Spring Cloud 环境中管理用于签名/验证 JWT 的私钥/公钥?

“问题”:

目前我生成了一个密钥对。然后将 Private + Public Key 复制到我的 auth-server 应用程序中。并将公钥复制到每个资源服务器。

当我现在想要实现“密钥轮换”时,我必须以某种方式为每个服务填充新密钥。


想法:

也许我可以使用spring-cloud-config-server 来存储和分发密钥对?

配置服务器已提供数据库登录凭据。那么为什么不在那里存储更敏感的信息呢?


问题:

如果这是要走的路:您将如何使用spring-cloud-config-server 实现密钥对分配?

您有任何安全问题吗?

你是如何解决这个问题的?我想有更好的解决方案。


编辑:

也许有一些使用 Spring Oauth 的 security.oauth2.resource.jwt.keyUri JWK 属性的解决方案?

【问题讨论】:

你见过Spring Vault吗? 还没有。感谢您的提示。现在我一直在看它,我并没有真正理解 Vault 和 Config Server 之间的区别。我也可以在 Config Server 中使用加密。 ...我的问题不是“保护私钥/公钥”。问题更像是“向我的服务分发公钥”。我的身份验证服务应该每 24 小时生成一个新的密钥对,用于签署 JWT,然后它需要以某种方式将新的公钥发布到所有其他服务(或者只是将其发布到配置服务器,所有其他服务将检索从那里)。 您是否同意这样做会拒绝所有之前生成的 JWT 令牌? 不,这行不通。我需要保留当前和以前的密钥对,然后(取决于令牌的过期时间戳)决定使用哪个密钥来验证 JWT。如果我拒绝以前生成的每个令牌,客户必须每天一次又一次地提供他的凭据。这对用户不友好。 ... EDIT: 应该足以保留公钥。每次轮换都可以丢弃私钥。 我的回答对您有帮助吗? 【参考方案1】:

首先,我会有一个网关来隐藏 JWT 机制。它将允许您从网关撤消令牌。如果用户知道他的令牌,你不能在不撤销公钥的情况下撤销它。它看起来像这样:

使用 zuul 的过滤器和会话范围的 bean 很容易实现。

其次,你在 cmets 中说过吗,你可以简单地创建一个新的私钥来生成新的令牌。但是您的所有资源服务器都必须能够读取所有先前生成的令牌。所以你需要在每个资源服务器上都有一个公钥列表,并且每次收到请求时,你都必须尝试用每个公钥来验证它。也许你可以有一个公钥 id(并将 id 放在每个生成的令牌上)以避免愚蠢地寻找这个任务。

对于密钥分发,使用 spring cloud bus 和 rabbit mq 对我来说似乎是正确的。

【讨论】:

我已经有一个网关,但它只会将请求转发到我的服务。前端和后端服务需要来自 JWT 的信息。当然,我可以使用网关将令牌交换为会话 ID,然后使用额外的 API 端点来检索令牌的内容。我的撤销机制对访问令牌使用较短的到期时间:客户端必须每 3 分钟使用一次刷新令牌,我可以在那里拒绝访问/“撤销”令牌。我不需要查看所有键。我只需要Map<ExpirationTimestamp, PublicKey> 即可找到令牌的正确密钥。 我目前在所有服务中使用 Spring 的 security.oauth2.resource.jwt.keyUri/oauth/token_key 在服务启动时检索当前令牌。到目前为止,这工作正常。但当然它只检索一个令牌一次,仅此而已。也许我应该复制和修改/oauth/token_key 的代码并提供Map<ExpirationTimestamp, PublicKey>。如果服务收到未知的 JWT 签名,它可以检查这个新 API 是否有新的公钥,然后重试验证签名。 @BenjaminM :我认为在前端阅读 JWT 是不安全的(如果它在浏览器上)。例如,如果您将令牌存储在 cookie 上,出于安全原因,cookie 必须是“httpOnly”,因此无法从 javascript 中读取。由于 spring-cloud-config 允许使用 yaml 文件,我认为您可以将键列表实现为对象列表:***.com/questions/33989612/… 当然是安全的。只要您不将其存储在本地存储中和/或容易受到 XSS 攻击。您还可以将 JWT 存储在 Cookie 中。然后你必须照顾 XSRF。安全没有金子弹。或者您使用“普通”会话 cookie,然后从另一个 URL 获取 JWT 的内容。一切都有优点和缺点。但这不是这里的主题。 ... 是的 Spring Config Server 可以使用 YAML(它只是 JSON 的超集)。但随后我必须弄清楚如何向服务发布新密钥。这是我的主要问题。其他一切都是不同的主题。 我不明白你的问题在哪里。您只需要在配置服务器上有新的密钥,然后执行器将完成刷新 bean 的工作。【参考方案2】:

您应该考虑改用Spring Cloud Consul Config:

Consul 提供 Key/Value Store 用于存储配置和其他 元数据。 Spring Cloud Consul Config 是 Config 的替代品 服务器和客户端。配置加载到 Spring 环境中 在特殊的“引导”阶段。配置存储在 /config 文件夹默认。多个 PropertySource 实例是 根据应用程序的名称和活动配置文件创建 模仿 Spring Cloud Config 解析属性的顺序。

您可以发布到 /refresh 以更新您的密钥,或 watch for changes:

Consul Config Watch 利用了 consul 的能力 观看一个关键前缀。 Config Watch 制作了一个阻塞的 Consul HTTP API 调用以确定任何相关配置数据是否已更改 当前的应用程序。如果有新的配置数据刷新 活动已发布。

【讨论】:

以上是关于Spring Cloud Security JWT:使用配置服务器/密钥轮换分发公钥的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Security JWT:使用配置服务器/密钥轮换分发公钥

Spring Cloud Security 实战,退出登录时如何借助外力使JWT令牌失效?

redis jwt spring boot spring security 实现api token 验证

基于Spring Security OAuth2搭建的Spring Cloud 认证中心

Spring Cloud Security Oauth2集成

带有 WSO2 身份服务器的 Spring Cloud Security