为什么 BFF 模式被认为对于 SPA 来说更安全?

Dje*_*eth 13 cookies access-token oauth-2.0 single-page-application refresh-token

我正在设计一个新的 Web 应用程序,需要 oAuth2 实现。我一直在阅读 PKCE 的 oAuth2 授权代码流程。这是有道理的,它确保启动授权代码流的客户端与交换访问令牌(和/或刷新令牌)的授权代码的客户端是同一客户端。

但后来我想知道我们如何处理刷新令牌。据我所知,BFF 现在是首选解决方案,我们使用一个单独的组件(前端的后端)来处理来自 Web 应用程序的所有调用并将这些调用代理到后端 api,同时处理所有访问令牌和刷新令牌。Web 应用程序和 BFF 维护一个会话 cookie,因此 BFF 可以跟踪应将哪个访问令牌添加到哪个请求等。

大多数博客都提到“如果您将会话 cookie 设置为严格且仅 http 且安全,这是安全的,因为这样恶意 JS 就无法获取该 cookie”。

这就是我难以理解为什么这更安全的地方。如果 cookie 足够安全来处理会话 ID,那么为什么它们不够安全来处理访问令牌呢?或者甚至刷新令牌?如果它们是基于 cookie 的,那么它们会随每个请求一起发送,并且恶意 JS 无法访问它。如果可以,那么 BFF 模型不会提供任何额外的安全性,只是稍微复杂一点,不是吗?

所以底线是:如果 BFF 被认为是安全的(r),因为会话保存在安全的仅 http cookie 中,为什么将访问/刷新令牌保存在安全的仅 http cookie 中不安全?

Mic*_*ski 21

添加 BFF 确实会改变使用代币的安全性。BFF 是一个机密客户端,因此它确实使整个解决方案更加安全,但这并不是您使用 BFF 的唯一原因。主要好处之一是让令牌远离浏览器。您不希望 Javascript 可以访问令牌,这就是您想要依赖基于 cookie 的会话的原因。这可以保护您免受想要窃取令牌的 XSS 攻击。但是,使用会话会使您面临 CSRF 攻击和会话骑乘攻击。防范 CSRF 和会话攻击应该比缓解 XSS 容易一些,因为例如,您可能会通过第三方库的依赖项而容易受到 XSS 的攻击。

\n
\n

例如,对于 BFF:从 cookie 窃取会话 -> 向 BFF 发出请求 -> 获取用户数据的访问权限。如果没有 BFF:从 cookie 中窃取 AT/RT -> 向 API 发出请求 -> 获取用户数据的访问权限。我仍然不明白这如何更安全,很抱歉不明白。

\n
\n

你不必感到抱歉!你尝试去理解这一点是件好事。

\n

您的示例的问题在于:您假设没有 BFF,但 AT/RT 保存在 cookie 中。如果您使用 cookie,则意味着您在 SPA 和 API 之间有某种后端组件。否则,您将不得不在浏览器中处理令牌(可由 JS 读取)。因此,您应该在这里考虑的区别是 \xe2\x80\x94 我是使用仅 HTTP cookie 来调用我的 API,还是需要令牌并在 JS 中设置授权标头?对于前一种情况,无论您在 cookie 还是实际 AT 中拥有会话 ID,都没有关系。重要的是 JS 无法读取该 cookie 的内容。

\n

另一件事是,窃取会话比保存在 JS 中的令牌更难。如果有人要从 cookie 中窃取数据,则需要进行浏览器中间人攻击。如果 JS 可以获取这些令牌,那么您只需要 XSS 攻击即可窃取它们。

\n

正如我提到的,使用 cookie 会让您面临 CSRF 和会话骑乘攻击,但它们的影响是有限的:

\n
    \n
  • 攻击者只能在用户打开会话时才能执行攻击。一旦用户关闭浏览器,就无法再窃取任何数据(而当攻击者窃取令牌时,只要令牌有效,他们就可以读取数据)
  • \n
  • 攻击者只能执行与用户从前端执行的操作相同的操作。对于被盗的 AT 来说也应该是这种情况,但实际上,访问令牌通常具有过于广泛的权限,并且您可以使用令牌调用一些通常无法从 UI 访问的 API。
  • \n
\n

在 Curity,我们花了一些时间研究这个问题,您可以查看我们撰写的有关 SPA 安全性以及不同方法的优缺点的白皮书:https://curity.io/resources/documents/single-page-应用程序安全白皮书

\n

  • 我从未感谢过您的回复和 Curity 资源。这是一本令人难以置信的有趣读物!只需在此留下此评论,以鼓励最终访问此页面的任何人阅读该白皮书! (2认同)

Han*_* Z. 9

BFF 被认为更安全,不是因为使用访问令牌时使用了 cookie,而是因为获取令牌的方式更安全。根据定义,SPA 无法保守秘密(在浏览器中),因此必须使用涉及公共客户端的流程。BFF 允许保密客户端,因为客户端秘密保存在后端。

对公共客户端使用 PKCE 确实可以保证请求和接收令牌的实体是同一实体,但它不能保证该客户端的真实性。后者由一位保密客户负责。