在 PKCE 增强的授权代码流中保护 code_verifier 的最佳实践
Posted
技术标签:
【中文标题】在 PKCE 增强的授权代码流中保护 code_verifier 的最佳实践【英文标题】:Best practice on Securing code_verifier in PKCE-enhanced Authorization Code Flow 【发布时间】:2021-08-03 15:08:51 【问题描述】:由于 PKCE 现在是推荐的隐式流授权方法,因此我正在寻找处理代码验证程序的最佳实践以及有关如何完成此操作的建议。高级 PKCE 授权流程包括:
-
在客户端生成
code_verifier
从 (1) 生成 code_challenge
点击/authorise
和code_challenge
重定向到选择idp 并且在回调中有一个code
使用 (3) 中的 code
和 code_verifier
交换访问令牌
问题是,在第 3 步中,在应用程序重定向到授权服务器和 idp 之前,必须将code_verifier
存储在某处。 那是什么地方?
似乎像okta-oidc-js
这样的库将code_verifier
存储在 sessionStorage 中。这不会让您受到 XSS 攻击吗?即如果我在应用程序进入授权流程并重定向之前将code_verifier
存储在sessionStorage中,在回调中,是什么阻止了一些胭脂扩展从url读取code
和从sessionStorage读取code_verifier
?两者的组合可用于交换访问令牌。
【问题讨论】:
【参考方案1】:您所描述的是标准的 SPA 做事方式 - 它可能会被恶意代码滥用,但授权代码只能使用一次并且验证程序不会长时间存储这一事实有一些保护措施.
相关的 XSS 攻击是在隐藏的 iframe 上运行完整的 OAuth 授权重定向 + 代码交换 - 无论涉及后端还是客户端密码,都没有针对这种情况的保护。
如果您想严格要求安全性,新兴趋势更多是前端方法的后端,其中后端是在https://api.mywebdomain.com 上运行的“代理 API”
OAuth授权的结果是API下发的同一个站点cookie,防止上述iframe攻击
然后 SPA 可以使用 auth cookie 获取访问令牌或通过代理 API 的双跳 API 请求。
最近有一个关于 SPA 安全性的精彩视频here 更深入地讨论了这些威胁。浏览器是一个难以实现安全性的地方,并且重定向会带来风险。
但仍建议将 Web 和 API 问题分开 - 例如,上述代理 API 不应妨碍希望通过内容交付网络部署其 SPA 的公司。
登录舞蹈
在我看来,首选方法总结如下,以实现完全控制,并且最近浏览器更改没有问题:
SPA 调用诸如https://api.mywebdomain.com/login/start 之类的 URL,它为 .mywebdomain.com 写入一个仅 HTTP 加密的 cookie,其中包含 state 和 code_verifier,并且还返回授权请求 URL
SPA 然后自己进行重定向,并在需要时将页面位置/状态预先保存到会话存储中
SPA 然后接收带有代码和状态的响应 URL,然后将它们发布到诸如 https://api.mywebdomain.com/login/end 之类的 URL。之后SPA可以恢复它的页面位置和状态,这样可用性就很好了。
API 通过根据状态 cookie 中的状态验证状态,然后使用状态 cookie 中的 code_verifier 来完成登录。所有这一切的结果是编写了一个无法在 iframe 上滥用的身份验证 cookie(包含刷新令牌)。
【讨论】:
那么建议在服务器端生成 code_verifier 存储为相同的站点 cookie (lax) 并在客户端完成重定向后让服务器执行令牌交换代码...?跨度> 另外,为什么推荐用于网站(spa 或其他)PKCE 的 oauth 流?当客户负责创建和使用 code_verifier 时,规范没有提及或建议在哪里存储它 视频非常有用? 只是为了完成 - PKCE 很好,因为它是 OAuth 2.1 建议。它可以在服务器端生成并存储在状态 cookie 中,然后再使用。我在上面的部分中添加了我目前对流程应该如何工作的想法。我认为在解决这个安全问题时不要失去 SPA 架构的优点很重要。以上是关于在 PKCE 增强的授权代码流中保护 code_verifier 的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章
在带有 PKCE 的 OAuth 授权流中使用时如何在 Azure 应用注册中启用 CORS?
如何在 Kotlin 中使用 PKCE 实现 Spotify 授权代码
使用 PKCE 的授权代码流如何比没有 client_secret 的授权代码流更安全