用于 SPA 的验证码授权 /w PKCE

信息安全 oauth2 开放式连接 单页应用
2021-09-09 03:55:34

我是一个试图找出如何保护我的 SPA 的安全新手,并且完全迷失在 RFC、BCP、草稿和博客文章的森林中。如果可能的话,我想从 CDN 静态地提供我的 SPA。起初我被Okta这篇文章所鼓舞,它解释了为什么以及如何用代码+PKCE 流替换隐式流。然而,这个BCP 草案似乎也很有希望(强调我的)......

然后浏览器中的代码使用上面的 PKCE 扩展(在第 7 节中描述)(B)启动授权代码流,并通过 POST 请求(C)获取访问令牌。然后,JavaScript 应用程序负责使用适当的浏览器 API 安全地存储访问令牌

使用适当的浏览器 API 安全地存储访问令牌——这甚至可能吗?

如果我理解正确的话,公共客户端的代码+PKCE流程只比隐式流程好,因为它没有将访问令牌放在地址栏和历史记录中,但它仍然存在令牌需要存储的缺点在 localstorage/sessionstorage/non-httponly-cookies 中。

对?

所以我仍然容易受到 XSS 和恶意浏览器扩展的攻击。

我正在考虑两种选择:

  1. 使用为我的公共 SPA 客户提供服务的机密客户端后端。机密客户端在反向通道中接收令牌,并将它们设置为 HttpOnly-cookies。公共客户端现在可以与受保护的资源对话,而无需在每个请求上使用机密客户端作为代理。
  2. 将令牌存储在机密客户端后端,以便它们永远不会到达公共客户端。相反,公共客户端会获得一个会话 cookie,引用令牌。公共客户端将需要使用机密客户端作为对受保护资源的每个请求的代理。

将令牌存储在 HttpOnly-cookies 中似乎比将它们存储在 localstorage/sessionstorage 中要好得多,但代价是从机密客户端而不是直接从 cdn 提供 SPA。

对这些方法有什么建议吗?是否有任何文献更深入地解释了这些方法(或其他规范方式)?

2个回答

我想添加评论,但我是新来的,没有足够的代表...

关于长期刷新令牌,您不应该继续使用基于 PKCE 的 SPA。它应该仅是访问令牌和 id 令牌(对于承载)或可能仅是 id 令牌(对于 JWT 无状态)。根据定义,两者的寿命都应该很短,没有刷新的可能性。相反,您应该使用 openid 规范中定义的 iframe 来“刷新”访问 ID 令牌,而不使用刷新令牌。

下面是一个实现 iframe 逻辑的 angular lib 示例:https : //manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/refreshing-a-token.html 查看隐式流程,静默刷新逻辑。

如果您真的想在 SPA 上使用带有 PKCE 的刷新令牌,您应该满足的要求在这里:https ://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13第 4.12 节. 确保身份验证服务器正确实现了刷新令牌逻辑。

Auth0 建议将令牌存储在 JavaScript 内存中:

Auth0 建议将令牌存储在浏览器内存中作为最安全的选项。使用 Web Worker 处理令牌的传输和存储是保护令牌的最佳方式,因为 Web Worker 运行在与应用程序的其余部分不同的全局范围内。

如果您不能使用 Web Workers,Auth0 建议您使用 JavaScript 闭包来模拟私有方法。

这样做意味着令牌不会通过页面刷新保留,因此它意味着使用静默身份验证,其中令牌在刷新后在后台静默获取。这可以通过prompt=none授权调用的 OIDC 参数来完成。