Oauth2隐式授权流程和第三方Cookie中的刷新令牌

时间:2019-02-21 11:18:48

标签: oauth oauth-2.0 architecture jwt cloudfoundry-uaa

我想知道如何处理Oauth2隐式授予中的刷新令牌 当主要浏览器默认情况下禁用第三方Cookie时,将在2019年开始流动。

一些细节:

当前设置:

  • ui.example.com下的UI SPA应用

  • 身份提供者(CloudFoundry的UAA)在uaa.api.example.com

场景:

  • 用户登录时,身份提供商会使用域uaa.api.example.com的用户详细信息设置cookie,并在重定向的Location标头中返回JWT。

  • JWT存储在本地存储中(用于ui.example.com),但仅在1小时内有效,因此我想刷新它。

  • 通过向prompt=none发送到IDP授权端点的查询参数,可以刷新
  • (过程在Auth0 guide (it's not UAA but flow is the same中有很好的描述)

  • 在src设置为uaa.api.exmaple.com/oauth/authorize?prompt=none的每20m隐藏iframe中创建
  • ,这将启动登录过程,而无需用户提供其凭据。流程结束时,响应中返回的新JWT将再次存储在本地存储中。

问题:

  • 当允许使用第三方cookie时,浏览器会将IDP的cookie添加到iframe发出的请求中,因此流程可以正常工作,并且我在响应中获得了新令牌。

  • 在浏览器的设置中禁用了第三方Cookie时,iframe无法访问自己的Cookie,因此返回错误login_required而不是新的JWT。 iframe无法访问Cookie使得无法使用令牌续签

问题:

我的第三方Cookie是否有解决方案?

如果没有,我是否可以使用隐式授权流程和SPA替代方案来登录和刷新令牌?

4 个答案:

答案 0 :(得分:0)

作为您的应用程序和身份服务器托管在另一个域中。这意味着您的应用程序正在执行跨域身份验证。跨域身份验证是使用第三方Cookie来实现的,禁用第三方Cookie会使跨域身份验证失败。

回答您的问题:

我的第三方Cookie是否有解决方案?

  

在同一目录下托管您的应用程序和身份服务器   域。在这种情况下,您可以使用子域。

如果没有,我是否可以使用隐式授权流程和SPA替代方案来登录和刷新令牌?

  

解决方案:

我对CloudFoundry不熟悉。不确定他们是否支持。您可以通过在身份提供者端启用自定义域来解决此问题。因此,您的应用程序和身份提供者都将在同一个域中,并且cookie被视为第一方。例如,将应用程序托管在https://acme.com并将身份提供者自定义域设置为https://login.acme.com

答案 1 :(得分:0)

  

问题:

     

我的第三方Cookie是否有解决方案?

如果您在应用程序和IDP之间使用相同的顶级域,那么禁用第三方Cookie时应该没有问题。 This link还详细介绍了使用跨域策略获得成功的情况。

  

如果没有,则是否有隐式补助金流程和SPA的替代方案   我可以用来登录和刷新令牌?

我以前没有使用过CloudFoundry,但是大多数大型OAuth2.0提供程序都提供了公共客户端功能,其中公共客户端(例如您的SPA)不需要客户端密码来获取访问/刷新令牌。这使公共客户端可以使用Authorisation Code Grant,它可以允许通过刷新令牌来刷新令牌,从而避免了使用HTTP重定向和cookie的 silent auth 技术。

答案 2 :(得分:0)

问题的根源是使用iframe和隐式授予类型。

我认为您使用iframe的原因是跨域访问Cookie。现在,避免使用iframe的最简单方法是将cookie的域设置为Domain=example.com,并在example.com上同时具有UI和授权服务器。如果由于某种原因您不能执行此操作,则需要采用以下方法。


推荐选项

隐式授予类型不安全。尽管此问题与赠款类型的优缺点无关,但为了设置我将要解释的选项的背景,让我简要列举一下为什么我认为隐式流程不安全的原因:

  1. 缺少提供客户端密码和授权代码的客户端身份验证步骤。安全性降低
  2. 访问令牌作为URL片段发送回(以便令牌不会发送到服务器),它将继续保留在浏览器历史记录中
  3. 如果发生XSS攻击,恶意脚本可以很好地将令牌发送到远程服务器以控制攻击者

因此,建议的选项是使用授权码授予类型。在SPA(单页应用程序)中不使用授权码的原因之一是,它要求将客户端机密存储在浏览器中,并且我们知道浏览器无法保存机密。通过在服务器端具有代理组件(可以嵌入到资源服务器中)来保护客户端机密并充当SPA与授权服务器之间的代理,可以非常轻松地减轻这种风险。

(在授权码授予类型中)流程如下:

  1. 用户单击SPA登录页面上的登录按钮
  2. 用户将被重定向到授权服务器登录页面。 URL查询参数中提供了客户端ID
  3. 用户输入其凭据,然后单击“登录”按钮。用户名和密码将使用HTTP POST发送到授权服务器。凭据应在请求正文或标头中发送,而不应在URL中发送(因为URL已记录在浏览器历史记录和应用程序服务器中)。另外,应设置适当的缓存HTTP标头,以便不缓存凭据:Cache-Control:不缓存,不存储,Pragma:不缓存,Expires:0

  4. 授权服务器根据用户数据库(例如LDAP服务器)对用户进行身份验证,在该数据库中,用户名和用户密码的哈希(哈希算法(如Argon2,PBKDF2,Bcrypt或Scrypt)与随机盐一起存储)

  5. 成功进行身份验证后,授权服务器将根据URL查询参数中提供的客户端ID从其数据库检索重定向URL。重定向URL是资源服务器URL
  6. 然后将使用URL查询参数中的授权代码将用户重定向到资源服务器端点
  7. 然后,资源服务器将向授权服务器发出HTTP POST请求以获取访问令牌。授权代码,客户端ID,客户端机密应放在请求正文中。 (应使用上述适当的缓存头)
  8. 授权服务器将在响应正文或标头中返回访问令牌和刷新令牌(具有上述适当的缓存标头)
  9. 资源服务器现在将通过将域属性设置为Domain=example.com来设置适当的Cookie,从而将用户(HTTP响应代码302)重定向到SPA URL(假设资源服务器和UI都位于的子域中) example.com)。授权服务器的域无关紧要,因为它没有设置任何cookie。

以相同的方式,访问令牌刷新的请求可以发送到代理组件,该代理组件将从cookie中读取刷新和访问令牌,并使用由此提取的令牌,客户端ID和客户端调用授权服务器api。客户机密。

答案 3 :(得分:0)

最后,我们决定采用其他解决方案。当JWT生命周期结束时,我们显示一个模式通知会话已超时,并带有2个按钮,一个按钮用于注销,另一个按钮用于保持会话。当用户单击“保留会话”时,将打开新的选项卡/弹出窗口,在该选项卡中,可以通过再次提供其凭据或在IDP会话仍处于活动状态时自动提供其凭据来在IDP中对用户进行重新认证。

所以流程是:

JWT lifetime ends-> 'keep session' in modal chose-> open new tab/popup-window with IDP login form-> successfully authenticated-> redirect back to app-> store token in browser's storage-> close popup-window/tab with window.close() -> get new token from storage and use it in next calls

由于我们使用新的弹出窗口/选项卡重新进行身份验证,因此第三方Cookie没问题。

这也提供了一个巨大的优势。用户无论何时回到应用程序都不会失去工作,因为模式将在那里等待。我认为,此外,它还使我们满足了Re-authenticing accessibility success criterion (level AAA)

  

成功标准2.2.5重新认证

     

经过身份验证的会话到期时,用户可以在重新进行身份验证后继续活动,而不会丢失数据。