什么是刷新令牌安全性的良好微服务友好技术?
What is a good microservice-friendly technique for refresh token security?
我有一个 OAuth2 驱动的授权系统,用于我的生态系统中使用授权代码流的应用程序。目前,它按照我认为的最佳实践运行得非常好。我目前的流程可以总结为:
- 用户在应用程序前端单击登录按钮。
- 应用程序后端在参数中使用重定向 URI、客户端 ID 等将用户重定向到 Auth Server 登录页面。
- 用户登录,Auth Server 使用授权码重定向到后端 /authcode 端点。
- 后端使用授权码进行身份验证,接收访问 (JWT) 和刷新令牌。它将刷新令牌存储在自己的数据库中,returns 访问令牌作为 HTTP-Only cookie。
- 当Access token过期时,Backend发送Refresh token给Auth Server进行刷新。
这种方法的问题在于它严重依赖于 single-backend/monolith/etc 体系结构。当访问令牌过期时,有问题的后端应用程序需要能够获取刷新令牌,然后对 Auth 服务器进行刷新。
我对这个架构的未来状态的目标是由两个主要问题驱动的:
- 允许将后端拆分为多个微服务,这些微服务都能够验证同一个 JWT。
- 支持单点登录。目前,即使所有用户都通过相同的 Auth Server 进行管理并使用相同的凭据,他们也需要为他们登录的每个应用程序分别输入这些凭据。
我最初的想法是将刷新处理移至架构的客户端部分。由于所有应用程序都归我所有,我可以设置一个新流程,用户可以直接使用 Auth Server 登录,然后将访问 (JWT) 和刷新令牌设置为 HTTP Only cookie。我的所有应用程序都通过单个域名托管(不同应用程序具有不同的根 URI 路径)这一事实进一步支持了这一点。新的令牌结构将决定给定用户可以访问哪些应用程序。
我担心的是如何保护刷新令牌客户端。我很可能需要使用 Path 属性并依赖于我的所有应用程序都在同一个主机名上这一事实,正如我所说的那样,它们不会改变。
我想这个 post 的重点是我正在寻找处理这种情况的最佳实践指南。
基于我们在 Curity 推荐的设计模式的一些想法:
后端和 JWT
相关 API 应该能够相互转发 JWT 访问令牌,如 scopes article. Validating the JWT in each API results in a recommended zero trust 设置中所述。
后端换前端
我们推荐一种特殊的方法来做到这一点,专注于分离网络和 API 问题 - 请参阅 this code example 令牌处理程序模式。
令牌刷新通过 HTTP Only cookie 和 client side retries 处理。这提供了一种易于管理的无状态解决方案,其中 Web 后端仅为静态内容,例如内容分发网络。不过,它需要部署几个实用程序 API 组件。
如您所说,另一种选择是在后端编写代码来存储令牌,以便 cookie 仅包含一个会话 ID。
Cookie 和多个 Web 应用程序
在我们的资源中,我们使用反向代理/API 网关作为 API 的入口点,而不是 Web 后端。然后可以通过网关插件管理常见的管道,例如将 cookie 转换为令牌 - 如 this tutorial.
中所述
但是,当您有多个 Web 应用程序时,您需要在 API 请求期间隔离 cookie。因此,每个应用程序都需要自己的 API 路由。这很尴尬,但这是需要使用安全 cookie 以获得最佳浏览器安全性的结果。最好在网关中管理,单独的域或子域通常是最干净的:
然后每个网络团队负责自己的 API 路由和 cookie / CORS / CSRF 东西,而不是 API 开发人员。
单点登录
这应该完全由身份提供者会话 cookie 决定,它在您浏览应用程序时将保持有效。如果您在应用程序还没有安全 cookie 时显示登录按钮,那么感觉起来不像 SSO。使 SSO 看起来无缝的一种技术是让每个应用程序在还没有应用程序 cookie 时自动重定向,而不是显示登录按钮。
摘要
答案很长,但最好的解决方案需要分离并不总是很明显的关注点。做得好,最终结果应该是应用程序中的简单代码、正确的安全性和可扩展的架构。
我有一个 OAuth2 驱动的授权系统,用于我的生态系统中使用授权代码流的应用程序。目前,它按照我认为的最佳实践运行得非常好。我目前的流程可以总结为:
- 用户在应用程序前端单击登录按钮。
- 应用程序后端在参数中使用重定向 URI、客户端 ID 等将用户重定向到 Auth Server 登录页面。
- 用户登录,Auth Server 使用授权码重定向到后端 /authcode 端点。
- 后端使用授权码进行身份验证,接收访问 (JWT) 和刷新令牌。它将刷新令牌存储在自己的数据库中,returns 访问令牌作为 HTTP-Only cookie。
- 当Access token过期时,Backend发送Refresh token给Auth Server进行刷新。
这种方法的问题在于它严重依赖于 single-backend/monolith/etc 体系结构。当访问令牌过期时,有问题的后端应用程序需要能够获取刷新令牌,然后对 Auth 服务器进行刷新。
我对这个架构的未来状态的目标是由两个主要问题驱动的:
- 允许将后端拆分为多个微服务,这些微服务都能够验证同一个 JWT。
- 支持单点登录。目前,即使所有用户都通过相同的 Auth Server 进行管理并使用相同的凭据,他们也需要为他们登录的每个应用程序分别输入这些凭据。
我最初的想法是将刷新处理移至架构的客户端部分。由于所有应用程序都归我所有,我可以设置一个新流程,用户可以直接使用 Auth Server 登录,然后将访问 (JWT) 和刷新令牌设置为 HTTP Only cookie。我的所有应用程序都通过单个域名托管(不同应用程序具有不同的根 URI 路径)这一事实进一步支持了这一点。新的令牌结构将决定给定用户可以访问哪些应用程序。
我担心的是如何保护刷新令牌客户端。我很可能需要使用 Path 属性并依赖于我的所有应用程序都在同一个主机名上这一事实,正如我所说的那样,它们不会改变。
我想这个 post 的重点是我正在寻找处理这种情况的最佳实践指南。
基于我们在 Curity 推荐的设计模式的一些想法:
后端和 JWT
相关 API 应该能够相互转发 JWT 访问令牌,如 scopes article. Validating the JWT in each API results in a recommended zero trust 设置中所述。
后端换前端
我们推荐一种特殊的方法来做到这一点,专注于分离网络和 API 问题 - 请参阅 this code example 令牌处理程序模式。
令牌刷新通过 HTTP Only cookie 和 client side retries 处理。这提供了一种易于管理的无状态解决方案,其中 Web 后端仅为静态内容,例如内容分发网络。不过,它需要部署几个实用程序 API 组件。
如您所说,另一种选择是在后端编写代码来存储令牌,以便 cookie 仅包含一个会话 ID。
Cookie 和多个 Web 应用程序
在我们的资源中,我们使用反向代理/API 网关作为 API 的入口点,而不是 Web 后端。然后可以通过网关插件管理常见的管道,例如将 cookie 转换为令牌 - 如 this tutorial.
中所述但是,当您有多个 Web 应用程序时,您需要在 API 请求期间隔离 cookie。因此,每个应用程序都需要自己的 API 路由。这很尴尬,但这是需要使用安全 cookie 以获得最佳浏览器安全性的结果。最好在网关中管理,单独的域或子域通常是最干净的:
然后每个网络团队负责自己的 API 路由和 cookie / CORS / CSRF 东西,而不是 API 开发人员。
单点登录
这应该完全由身份提供者会话 cookie 决定,它在您浏览应用程序时将保持有效。如果您在应用程序还没有安全 cookie 时显示登录按钮,那么感觉起来不像 SSO。使 SSO 看起来无缝的一种技术是让每个应用程序在还没有应用程序 cookie 时自动重定向,而不是显示登录按钮。
摘要
答案很长,但最好的解决方案需要分离并不总是很明显的关注点。做得好,最终结果应该是应用程序中的简单代码、正确的安全性和可扩展的架构。