【发布时间】:2021-03-09 06:16:40
【问题描述】:
我正在开发的单页应用程序遇到了一些棘手的情况。
SPA 当前使用 JWT 令牌来访问两个不同域上的几个无状态(无会话)API 后端。
正常用户流程的典型(简化)示例是:
- 用户加载“spa.com”并下载 SPA 应用。
- 用户向 SPA 提供用户名/密码,SPA 向“api.spa.com/auth”发出 API 请求
- 此端点向 SPA 返回一个签名的 JWT,然后将其存储在 localStorage 中。
- 此 JWT 将作为标头添加到 SPA 发出的任何其他 API 请求中。
- SPA 现在可以访问具有相同 JWT 的两个单独的 API 域,“api.spa.com”和“api.otherdomain.com”
- 由于这两个 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