Authentication 用于多域API的浏览器访问令牌存储

Authentication 用于多域API的浏览器访问令牌存储,authentication,cookies,jwt,microservices,access-token,Authentication,Cookies,Jwt,Microservices,Access Token,我在开发一个单页应用程序时遇到了一些棘手的情况 SPA目前使用JWT令牌访问两个不同域上的两个无状态(无会话)API后端 正常用户流的典型(简化)示例为: 用户加载“spa.com”并下载spa应用程序 用户向SPA提供用户名/密码,SPA向“API.SPA.com/auth”发出API请求 该端点向SPA返回一个签名的JWT,然后SPA将其存储在localStorage中 此JWT作为标头添加到SPA发出的任何其他API请求中 SPA现在可以使用相同的JWT“API.SPA.com”和“API

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

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

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

  • 用户加载“spa.com”并下载spa应用程序
  • 用户向SPA提供用户名/密码,SPA向“API.SPA.com/auth”发出API请求
  • 该端点向SPA返回一个签名的JWT,然后SPA将其存储在localStorage中
  • 此JWT作为标头添加到SPA发出的任何其他API请求中
  • SPA现在可以使用相同的JWT“API.SPA.com”和“API.otherdomain.com”访问两个单独的API域
  • 由于这两个API域都共享JWT机密,因此它们可以验证JWT声明并允许访问它们的资源
  • 这非常有效,因为两个独立的API服务器都可以验证和响应来自SPA的请求,而不必在它们之间进行通信。然而,从安全角度对此配置进行了一些研究后,似乎认为在localStorage中存储访问令牌是不安全的,因为它极易受到XSS攻击

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

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

    对于这种情况,我还没有看到任何地方描述过最佳实践

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

    • sameSite不起作用,因为两个API域都需要访问 代币
    • 删除httpOnly(让应用程序访问令牌,传递到第二个API)可以通过XSS嗅探访问令牌,并且不会比localStorage更安全
    • 我们的框架提供的CSRF解决方案默认情况下需要加密cookie内容,因此通过第二个API无法读取cookie内容。(身份验证API是用Rails编写的,但我不确定这是否与根本问题相关)
    我们还可以研究其他一些复杂的解决方案,例如构建一个API网关来代理一个域下的两个API,或者删除sameSite要求,并在第二个API服务器上重新实现cookie解密和反CSRF检查(这是有问题的,因为第二个API是在nodeJS中编写的)

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


    有没有人遇到过类似的情况,或者他们可以为我指出一些多域访问令牌身份验证的最佳做法?

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

    我已经添加了一些到我的博客文章和代码示例的链接,以及一些设计模式,它们可以帮助您实现自己的解决方案。要使SPA的安全性和可用性达到我们的利益相关者满意的水平,可能会很棘手

    简单代码示例

    令牌续订依赖于隐藏的iframe令牌续订,除非使用持久的SSO Cookie,否则在具有默认设置的Safari中可能无法工作

    复杂代码示例

    如果您想更进一步,可以参考一个更复杂的解决方案,其中包括:

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