OAuth2 授权代码流 - 在前端 VS 后端交换授权代码?
OAuth2 Authorization Code Flow - exchange authorization code on Frontend VS Backend?
我正在使用 Angular 前端和 Java/Spring-Backend 开发应用程序。为了登录到我们的后端,我们使用 Oauth2 授权代码流与 PKCE 和 Open ID Connect.
当用户导航到受保护的路由时,他将被重定向到他的 IDP 并必须登录。之后,他返回到 redirect_uri,authorization_code 作为 URL 参数。至此一切都清楚了。
现在我不确定用此代码交换 access_token 的最佳方法是什么?到目前为止,我已经在客户端(在 JavaScript 中)完成了此操作,并将接收到的 JWT 用于进一步的后端调用(在后端我只是验证签名)并且这似乎确实有效。但在其他项目中,我看到同事实际上使用了类似于代理的后端。所以他们将 authorization_code 发送到 Java-后端,后端进行交换。
现在我读了很多书,但似乎无法理解其中的全部含义。在我看来,让 client/frontend 这样做更安全。但另一方面,后端实际上是可信的,因此在这种情况下我们实际上可以使用 client_secret。
现在的问题是:这两种情况都被认为是安全的吗?还是一种被认为更安全,如果是这样:为什么?
提前致谢
*编辑:澄清一下——我们真的不需要访问另一个资源服务器,用例是我们只想安全地进行身份验证到我们自己的后端 - 一旦通过身份验证,我们无论如何都会切换到会话cookie,所以我们根本不会将access_token存储在任何地方
将令牌保留在后端始终是一种更安全的方法,因为它减少了攻击面并使客户端中的代码更加简单。
看一看这个 BCP 是一个很好的起点
- OAuth 2.0 for Browser-Based Apps(第 6.2 节)
另一个参考是:
为了使您的 JavaScript 简单,我会在后端进行所有客户端身份验证,当后端获得令牌时,然后创建与您的客户端的会话。这样 JavaScript 客户端就不需要触及任何令牌。您的内部 resources/API 将通过负责会话的服务访问。干净简单! :-)
是的!我认为典型的错误是让 JavaScript 触及你的令牌。知道令牌仅在后端处理,您晚上会睡得更好。此外,更少的安全复杂性和您必须掌握和理解的东西! 我们必须与复杂性作斗争!
当您从客户端调用令牌时,它不是授权流程,而是隐式流程,当您没有后端时可以使用它,而当您有后端时,您始终应该使用授权代码流程,因为您已经提到了。您可以了解有关 openid 流的更多信息 here.
授权代码流被认为更安全,因为它使用带有 idp 的反向通道通信(服务器到服务器)来接收令牌,而隐式流从浏览器发送请求。
使用 PKCE 发送客户端调用是一项新技术,它被认为是安全的,但绝对授权代码流是后端更好的选择。
实际授权码只能使用一次,所以无论是前端还是后端发送都无所谓
这里有两种常见的模型:
选项 1:Web 后端/代理模式
如果您想将令牌保留在浏览器之外并使用仅 HTTP cookie 作为后端凭证,则使用此选项:
- Web 后端发布一个相同域的 HTTP only cookie 并将令牌存储在数据库或 cookie 本身中
- Web UI 通过首先使用 cookie
调用 Web 后端来进行所有 API 调用
- Web 后端然后查找令牌并将它们转发到 API
- 您需要应对CSRF、XSS等Web威胁
挑战是:
- 比您想要的更复杂
- 一些架构限制
选项 2:SPA 模式
这是您正在使用的跨域模型,在技术上更简单一点::
- Web UI 通过发送访问令牌进行 API 调用
- 您需要应对 XSS 等威胁,并特别关注确保在浏览器中使用令牌的安全性不亚于使用 cookie
- 您需要在浏览器中以安全的方式存储令牌,例如在内存中
挑战是:
- 如果您在安全方面存在漏洞,它们将更容易被利用,因为用户可以更轻松地看到他们自己的令牌
- 令牌更新和交叉标签导航方面在此模型中比较棘手。
因素
这些是做出选择时的主要因素:
- 安全威胁模型 - 令牌与 cookie 和其他因素
- 更广泛的 Web 架构目标 UIs
- 利益相关者的看法通常是最重要的考虑因素
无论您做出什么决定,我都建议您从需求开始,而不是特定的技术堆栈。
我的资源
我更喜欢选项 2,因为我认为架构选项要好得多,但它需要小心。希望以下链接可以帮助您了解我是如何推理出我的首选解决方案的:
虽然不是每个人都同意我的看法。有时在软件中有多种解决方案。重要的是涵盖了安全威胁。您可以使用任一解决方案来做到这一点。
我正在使用 Angular 前端和 Java/Spring-Backend 开发应用程序。为了登录到我们的后端,我们使用 Oauth2 授权代码流与 PKCE 和 Open ID Connect.
当用户导航到受保护的路由时,他将被重定向到他的 IDP 并必须登录。之后,他返回到 redirect_uri,authorization_code 作为 URL 参数。至此一切都清楚了。
现在我不确定用此代码交换 access_token 的最佳方法是什么?到目前为止,我已经在客户端(在 JavaScript 中)完成了此操作,并将接收到的 JWT 用于进一步的后端调用(在后端我只是验证签名)并且这似乎确实有效。但在其他项目中,我看到同事实际上使用了类似于代理的后端。所以他们将 authorization_code 发送到 Java-后端,后端进行交换。
现在我读了很多书,但似乎无法理解其中的全部含义。在我看来,让 client/frontend 这样做更安全。但另一方面,后端实际上是可信的,因此在这种情况下我们实际上可以使用 client_secret。
现在的问题是:这两种情况都被认为是安全的吗?还是一种被认为更安全,如果是这样:为什么?
提前致谢
*编辑:澄清一下——我们真的不需要访问另一个资源服务器,用例是我们只想安全地进行身份验证到我们自己的后端 - 一旦通过身份验证,我们无论如何都会切换到会话cookie,所以我们根本不会将access_token存储在任何地方
将令牌保留在后端始终是一种更安全的方法,因为它减少了攻击面并使客户端中的代码更加简单。
看一看这个 BCP 是一个很好的起点
- OAuth 2.0 for Browser-Based Apps(第 6.2 节)
另一个参考是:
为了使您的 JavaScript 简单,我会在后端进行所有客户端身份验证,当后端获得令牌时,然后创建与您的客户端的会话。这样 JavaScript 客户端就不需要触及任何令牌。您的内部 resources/API 将通过负责会话的服务访问。干净简单! :-)
是的!我认为典型的错误是让 JavaScript 触及你的令牌。知道令牌仅在后端处理,您晚上会睡得更好。此外,更少的安全复杂性和您必须掌握和理解的东西! 我们必须与复杂性作斗争!
当您从客户端调用令牌时,它不是授权流程,而是隐式流程,当您没有后端时可以使用它,而当您有后端时,您始终应该使用授权代码流程,因为您已经提到了。您可以了解有关 openid 流的更多信息 here.
授权代码流被认为更安全,因为它使用带有 idp 的反向通道通信(服务器到服务器)来接收令牌,而隐式流从浏览器发送请求。
使用 PKCE 发送客户端调用是一项新技术,它被认为是安全的,但绝对授权代码流是后端更好的选择。
实际授权码只能使用一次,所以无论是前端还是后端发送都无所谓
这里有两种常见的模型:
选项 1:Web 后端/代理模式
如果您想将令牌保留在浏览器之外并使用仅 HTTP cookie 作为后端凭证,则使用此选项:
- Web 后端发布一个相同域的 HTTP only cookie 并将令牌存储在数据库或 cookie 本身中
- Web UI 通过首先使用 cookie 调用 Web 后端来进行所有 API 调用
- Web 后端然后查找令牌并将它们转发到 API
- 您需要应对CSRF、XSS等Web威胁
挑战是:
- 比您想要的更复杂
- 一些架构限制
选项 2:SPA 模式
这是您正在使用的跨域模型,在技术上更简单一点::
- Web UI 通过发送访问令牌进行 API 调用
- 您需要应对 XSS 等威胁,并特别关注确保在浏览器中使用令牌的安全性不亚于使用 cookie
- 您需要在浏览器中以安全的方式存储令牌,例如在内存中
挑战是:
- 如果您在安全方面存在漏洞,它们将更容易被利用,因为用户可以更轻松地看到他们自己的令牌
- 令牌更新和交叉标签导航方面在此模型中比较棘手。
因素
这些是做出选择时的主要因素:
- 安全威胁模型 - 令牌与 cookie 和其他因素
- 更广泛的 Web 架构目标 UIs
- 利益相关者的看法通常是最重要的考虑因素
无论您做出什么决定,我都建议您从需求开始,而不是特定的技术堆栈。
我的资源
我更喜欢选项 2,因为我认为架构选项要好得多,但它需要小心。希望以下链接可以帮助您了解我是如何推理出我的首选解决方案的:
虽然不是每个人都同意我的看法。有时在软件中有多种解决方案。重要的是涵盖了安全威胁。您可以使用任一解决方案来做到这一点。