【问题标题】:Browser access token storage for multi-domain APIs多域 API 的浏览器访问令牌存储
【发布时间】:2021-03-09 06:16:40
【问题描述】:

我正在开发的单页应用程序遇到了一些棘手的情况。

SPA 当前使用 JWT 令牌来访问两个不同域上的几个无状态(无会话)API 后端。

正常用户流程的典型(简化)示例是:

  1. 用户加载“spa.com”并下载 SPA 应用。
  2. 用户向 SPA 提供用户名/密码,SPA 向“api.spa.com/auth”发出 API 请求
  3. 此端点向 SPA 返回一个签名的 JWT,然后将其存储在 localStorage 中。
  4. 此 JWT 将作为标头添加到 SPA 发出的任何其他 API 请求中。
  5. SPA 现在可以访问具有相同 JWT 的两个单独的 API 域,“api.spa.com”和“api.otherdomain.com”
  6. 由于这两个 API 域共享 JWT 机密,它们可以验证 JWT 声明并允许访问其资源。

这非常有效,因为两个单独的 API 服务器都可以验证和响应来自 SPA 的请求,而无需在它们之间进行通信。但是,从安全角度对此配置进行了一些研究后,似乎将访问令牌存储在 localStorage 中被认为是不安全的,因为它极易受到 XSS 攻击。

关于该主题的大多数文章似乎都建议将 JWT 访问令牌存储在 httpOnly、sameSite=strict、受 CSRF 保护的 cookie 中。 (例如here 和here)

如果 SPA 只需要访问一个域(设置 cookie 的域),这会很好,但不幸的是,我们在两个需要访问的域上有两个 API。

我没有看到任何地方描述过这种情况的最佳实践。

我发现推荐的 cookie 方法存在一些问题:

  • sameSite 无法正常工作,因为两个 API 域都需要访问 令牌
  • 删除 httpOnly(让应用访问令牌,传递给第二个 API)让访问令牌无论如何都可以通过 XSS 嗅探,并且不比 localStorage 更安全。
  • 我们框架提供的 CSRF 解决方案涉及默认加密 cookie 内容,因此无法通过第二个 API 读取。 (身份验证 API 是用 Rails 编写的,但我不确定这与底层问题是否相关)

我们可以研究一些其他复杂的解决方案,例如构建一个 API 网关来代理一个域下的两个 API 或删除相同的站点要求,以及在第二个 API 服务器上重新实现 cookie 解密和反 CSRF 检查(这是有问题的,因为第二个 API 是用 nodeJS 编写的)。

但是,我有点希望有一个安全的解决方案,不会涉及像上面提到的那样剧烈的变化。

有没有人遇到过类似的情况,或者他们能给我指出一些多域访问令牌身份验证的最佳实践吗?

【问题讨论】:

    标签: authentication cookies jwt microservices access-token


    【解决方案1】:

    最简单的选择是将访问令牌仅存储在浏览器内存中而不是本地存储中。然后,如果用户刷新页面或进行多标签浏览,您需要处理静默令牌更新。

    我添加了一些指向我的博客文章和代码示例的链接,其中的一些设计模式可以帮助您制定自己的解决方案。将 SPA 的安全性和可用性提高到我们的利益相关者满意的水平可能会很棘手。

    简单代码示例

    令牌更新依赖于隐藏的 iframe 令牌更新,这可能无法在 Safari 中使用默认设置,除非使用持久性 SSO cookie。

    复杂代码示例

    如果您想更进一步,this blog post 中引用了一个更复杂的解决方案,其中涉及:

    • 将访问令牌存储在浏览器内存中
    • 将刷新令牌存储在仅 HTTP 加密的 Web 域 cookie 中

    【讨论】:

      猜你喜欢
      • 2017-10-19
      • 2018-11-15
      • 2019-05-06
      • 2020-03-14
      • 1970-01-01
      • 1970-01-01
      • 2023-04-07
      • 2019-11-16
      • 2012-07-18
      相关资源
      最近更新 更多