现代身份指南
Search…
⌃K

第十三章 用户注销

我们常常认为,注销是个很简单并且不重要的事情。它在整个项目中可能都会有特别的计划去安排。但实际上,实现注销的设计可能比登录还要复杂,以确保系统安全性的闭环。
对于一些敏感的应用,如金融交易或是医疗挂号等应用,尤其是使用共享设备的应用,登出尤为重要。如果用户已经完成操作,则终止会话可以消除会话被其他人劫持利用的风险。在设备丢失或者被盗的情况下,这些登录的机制将作为非常重要的安全机制来保障系统的安全。接下来,我们将详细介绍注销的复杂程度,已经设计注销时需要包含的内容和一些实现的选择。

多个会话

在使用单点登录的环境中实现注销可能很复杂,因为可能需要关心多个会话的状态。 图 13-1 显示了三种不同的场景,每种场景中都会产生用户的身份验证会话。 用户至少有一个应用程序会话(模型 1)。 如果应用程序将身份验证委托给身份提供商 (IdP),身份提供商可能会为用户提供一个活动会话(模型 2)。 如果应用程序使用身份验证代理,为了便于处理许多不同的身份提供商和协议,身份验证代理还可能为用户提供一个活动会话(模型 3)。 这意味着用户在登录后最多可以在解决方案架构的三个不同层中进行会话。身份提供者可以将身份验证委托给另一个身份提供者,因此可能涉及更多层,这种更为复杂的情况并不常见。
13-1 用户的多个会话
注销更加复杂,因为使用单点登录 (SSO),可能需要考虑更多会话。 如果用户可以通过 SSO 访问多个应用程序,则每个应用程序中都可能有一个额外的会话。 图 13-2 说明了这种可能性,其中显示了应用程序 A 和 B 将身份验证委托给身份验证代理的场景,该代理又将用户身份验证委托给身份提供者。 应用程序 C 将身份验证直接委托给身份提供者。 如果用户在短时间内访问应用程序 A、B 和 C,则该用户将有五个活动会话。
13-2 RP的会话

注销触发

任何用户会话的终止都可以由几个不同的事件触发。 最明显的是当用户单击应用程序中的注销按钮时。 如果身份提供商提供注销的按钮功能,用户还可以直接在身份提供商处触发其会话的注销。 除了用户发起的注销之外,管理员还可以在应用程序或身份提供者中终止用户的会话。 另一种可能性是,如果用户空闲或登录时间过长,则用户会话超时。 然后,应用程序或身份提供者可能会收到来自环境中另一个组件的注销请求。 当任何这些事件发生时,一个或多个用户的会话将被终止。 问题是——哪些应该被终止,在什么情况下被终止?

注销选项

当一个用户有多个会话时,有必要决定当用户的任何会话终止时会发生什么。 使用图 13-1 中描述的模型,如果用户在应用程序中的会话终止,根据会话存在的位置,终止以下一项或多项可能是合适的: • 应用会话 • 身份验证代理会话(如果使用代理) • 身份提供者会话
例如,在图 13-2 中,当用户注销应用程序 A 时,应用程序可以向身份验证代理发送注销请求。 身份验证代理可能有其他应用程序(依赖方)依赖其用户会话,例如图中的应用程序 B。 当它收到注销请求时,身份验证代理可以向应用程序 B 发送注销请求以终止用户在那里的会话。 此外,身份验证代理可以向身份提供者发送注销请求。 身份提供者会看到应用程序 C 依赖于它的用户会话,并且可以向应用程序 C 发送注销请求。
如果用户的会话因任何原因在身份提供者或身份验证代理处终止,则应评估相同的可能性。 再次使用图 13-2,如果用户的会话在身份提供者处终止,它可以向应用程序 C 和身份验证代理发送注销请求,因为它们都是身份提供者的依赖方。 类似地,如果用户的会话在身份验证代理处终止,它可以向身份提供者和/或依赖方应用程序 A 和 B 之一或两者发送注销请求。
在设计注销时,有必要考虑会话存在于何处,以及在用户发起注销或会话因其他原因终止时应终止哪些会话。 决定中的一个因素是拥有会话的实体。 在企业环境中,公司安全策略可能规定应用程序中的注销必须触发身份提供商会话的终止,并且可能触发其他应用程序中所有用户打开的会话。 然而,在用户通过社交提供者登录的面向消费者的环境中,应用程序注销终止用户在社交身份提供者处的会话可能不太合理或不可能。 显然,身份提供者或身份验证代理支持的注销功能是影响注销设计的另一个因素。
用户体验也是一个重要因素。 应注意避免给用户带来意外。 通过一次注销终止用户的所有应用程序以及 SSO 会话提供了一次性终止所有访问的便捷方式。 这在企业环境中可能是可取的,因为如果用户需要单独注销每个应用程序,会给用户带来很多麻烦,并且有可能有遗漏。 但是,如果用户不清楚此类注销的影响,这可能会突然中断依赖于同一 SSO 会话的用户其他应用程序会话而让用户产生抱怨。 一个例子将有助于说明这一点。
使用图13-2中的场景,如果用户同时在三个应用程序(A、B和C)中工作,从应用程序A注销会触发其会话的终止。如果用户对这一机制不了解,并且正在B或C中完成操作中的事务。如果其他应用程序中会话的突然终止B和C的会话,可能会导致用户在那里丢失工作。注销的实现决定了用户是否可以在其他应用程序中继续工作。
一种实现的方式是让应用程序 A 中的注销触发应用程序 B 和 C 中用户的立即注销。用户在应用程序 A 的会话的终止触发对身份验证代理的注销请求,身份验证代理配置为向相关联的应用发送该请求 ,在其会话终止时,向应用程序 B 发出注销请求。身份验证代理还可以向身份提供者发送注销请求,后者又可以向应用程序 C 发送注销请求。这些注销消息将有效地终止所有用户的会话 三个应用程序,身份验证代理和身份提供者。
另外一种实现是,当应用程序 A 向身份验证代理发送注销请求时,代理可以简单地为用户终止其自己的会话。 在这种情况下,用户可以继续在应用程序 B 中工作,直到用户在应用程序 B 中的会话超时。 超时后,应用程序 B 将检查用户的会话在 SSO 服务器上是否有效。 如果用户在 SSO 服务器中的会话已终止,则用户需要重新登录才能继续访问应用程序 B。
关于终止哪个会话的决定特定于每个环境,应考虑拥有会话的实体、用户体验、应用程序的敏感性以及在用户离开时关闭会话的安全考量。 实施注销后,应对其进行彻底测试,以确保其按设计工作。 我们可以提供的最佳建议是在您的项目中留出足够的时间来设计和测试注销,并尽早的开始,因为这可能需要比预期更多的时间。 如图 13-1 所示,除应用程序之外的其他实体(例如身份验证代理)可能是身份提供者的依赖方。 因此,在后续部分中,我们将在某些地方使用更广泛的术语“依赖方”而不是“应用程序”来识别可能受注销影响的所有类型的实体。

应用注销

最简单的实现是本地应用程序注销,即在一个单独的应用程序中终止用户的会话。 对于应用程序注销,当发生前面部分中描述的任何注销触发器时,应用程序需要删除应用程序设置的任何应用程序会话信息、令牌和浏览器 cookie。 如果使用来自支持访问令牌撤销的授权服务器的 OAuth 2.0 访问令牌,则应通过授权服务器的撤销端点撤销它们。 刷新令牌(如果使用)也应撤销。 本地应用程序注销本身不会影响用户可能在身份提供者或身份验证代理处建立的任何其他经过身份验证的会话,但是当触发本地应用程序注销时,应用程序可以选择向此类其他组件发送注销请求消息。

Oauth2.0

OAuth 2.0 不包含注销端点,因为它旨在授权 API 调用,而不是对用户进行身份验证。 尽管如此,在用户会话终止后,应用程序应尽可能清理与用户相关的安全令牌。 应用程序可能已经获得了 API 的访问令牌,也可能获得了刷新令牌。 OAuth 2.0 规范表明授权服务器应该提供一种机制来撤销访问令牌i,OAuth2.0 令牌撤销规范为此定义了一个标准。 然而,提供访问令牌撤销机制不是强制性的,因此某些授权服务器实现可能不支持这一点。
如果授权服务器支持访问令牌撤销,则当用户注销或会话因任何其他原因终止时,应用程序应使用其撤销端点来撤销用户为该应用程序授权的访问令牌。 如果无法撤销访问令牌,则应撤销刷新令牌,以避免应用在访问令牌过期时利用刷新令牌继续获取新的访问令牌。 如果没有刷新令牌,当先前颁发的访问令牌过期时,应用程序将无法获得新的访问令牌。 无法撤销访问令牌的应用程序必须依靠访问令牌到期来终止应用程序调用 API 的能力。 这强调了短期访问令牌的好处。

OIDC

原始 OIDC 规范没有为应用程序在 OpenID 提供者处请求终止用户会话定义明确的注销机制,也没有为 OpenID 提供者在 OpenID 提供者的会话终止时通知依赖方的方式定义。 然而,在撰写本文时,OIDC 注销的规范草案值得关注,需要注意的是,规范草案可能无法获得批准状态或可能在批准前发生变化。 实施前应该查阅您的 OIDC 提供商的文档和有关任何草案规范的计划。
OpenID Connect 会话管理规范草案 ii定义了依赖方发起的注销流程,以便在依赖方注销时,依赖方可以向 OIDC 提供商发送注销请求以终止其用户会话。 接收注销请求的 OpenID 提供者可以与用户确认他或她希望注销 OIDC 提供者会话。 此确认功能有助于防止无意中终止用户在其他应用程序中可能仍需要的会话。
OpenID Connect 会话管理iii 规范草案还为依赖方应用程序提供了一种解决方案,以检测 OpenID 提供者会话何时终止。 它旨在使用从 OpenID 提供程序加载的隐藏 iframe,并且可以从 OpenID 提供程序访问浏览器状态。 此 iframe 是从依赖方应用程序加载的另一个隐藏 iframe 轮询的,如果用户在 OpenID 提供程序上的会话已更改,则会收到“已更改”状态。 如果发生这种情况,依赖方应用程序可以使用 prompt=none 通过新的身份验证请求将用户重定向到 OpenID 提供者,如果此请求收到错误响应,则表明 OpenID 提供者处的用户会话不再有效。 然后,如果合适,应用程序可以为用户终止其会话。
OpenID Connect Front-Channel 注销的提案草案iv为 OpenID 提供者提出了一种解决方案,用于向依赖方应用程序发送注销请求,这些请求可用于在 OpenID 提供者会话终止时通知他们。 Front-Channel 注销依赖于应用程序和 OpenID 提供者之间的通信,通过在它们之间用户的浏览器进行重定向,这种方式可以无视防火墙的阻隔,但有两个缺点。 如果用户已离开浏览器中的应用程序,则对该应用程序的 Front-Channel 注销请求将失败,并且仅当用户使用浏览器的后退按钮返回该应用程序时,该应用程序中的用户会话才会被注销。 此外,Front-Channel 注销的一系列重定向失败可能会导致注销流程无法顺利完成。
OpenID Connect Back-Channel 注销规范草案v为 OpenID 提供者提供了一种解决方案,可以通过服务器之间的后端通信而不是通过前端浏览器重定向向依赖方发送注销请求。当有许多依赖方时,这可以提供比 Front-Channel 注销更可靠的注销选项。对于此解决方案,依赖方向 OpenID 提供者注册一个后端注销 URI。 OpenID 提供者记住用户通过其 OpenID 提供者会话登录的所有依赖方。当用户的 OpenID 提供者会话终止时,OpenID 提供者会向用户在会话期间访问的每个依赖方发送一个注销请求,该请求格式为 JWT 并称为注销令牌。注销令牌通过反向通道通信(服务器到服务器)使用 HTTP-POST 发送到先前向 OpenID 提供者注册的依赖方的后端通道注销 URI。在接收并验证注销令牌后,依赖方会为用户删除其会话并向 OpenID 提供者返回状态响应。此解决方案需要 OpenID 提供者和依赖方的后端通道注销 URI 之间的直接连接。这对于驻留在防火墙后面的本地企业环境中的应用程序来说可能会存在防火墙隔离的问题。
依赖方应用程序还可以通过将用户的浏览器重定向到 OpenID 提供者并将身份验证请求中的提示参数设置为“none”来定期轮询 OpenID 提供者,从而检测到用户在 OpenID 提供者处会话的终止。 如果用户在 OpenID Provider 上没有有效的会话,将返回错误状态响应,应用程序可以在应用程序中终止用户的会话或再次重定向用户以重新验证和更新他们的会话。 这种方法的缺点是重定向会中断用户体验。 重复轮询 OpenID 提供者也可能存在达到速率限制的风险。
一个经常被拷问的问题是是否能够快速终止用户对应用程序的访问。 比如,员工被解雇,或者发现账号泄漏的情况下,公司是否能够快速的终止该用户的所有会话。 如果 支持 OpenID 提供者在会话终止时通知依赖方的功能,则可以实现此功能。 如果没有这种单点注销功能的情况下,应用程序可以定期轮询 OpenID 提供者,如前所述。 如果此时用户在 OpenID 提供程序中的帐户已被禁用,则应用程序将不会收到续订会话所需的成功响应。 这也可以有效地终止用户使用应用程序的能力,至少在容忍周期等于应用程序的轮询频率的情况下可以达到该目的。

SAML 2.0

使用 SAML 2.0,服务提供商应用程序可以通过向身份提供商发出注销请求消息来终止用户在身份提供商处的会话。 收到注销请求消息后,身份提供者终止其为用户持有的会话,该会话由请求中的主题标识符和可能的会话会话标识符标识。 身份提供者还可以在用户浏览器中更新或删除其会话 cookie。 然后,身份提供者使用注销响应消息响应应用程序。
如果用户的会话在身份提供者处终止,SAML 2.0 还为身份提供者提供了一种通知其他依赖方的方法。 在身份提供者会话终止或从服务提供者接收到注销请求消息后,身份提供者可以将注销请求消息发送到具有用户活动会话的每个其他依赖方。 依赖方应该终止他们的会话并向身份提供者发送注销响应消息。 如果全局注销是由一个服务提供商发起的,则身份提供商向发起注销的依赖方返回注销响应消息。 这种交互如图 13-3 所示。
​图13-3 SAML Logout交互​
  1. 1.
    用户在应用程序 A(依赖方)处发起注销。
  2. 2.
    应用程序 A使用 SAML 注销请求消息将用户浏览器重定向到身份提供者。
  3. 3.
    身份提供者向其他依赖方发送 SAML 注销请求消息,例如应用程序 B。
  4. 4.
    应用B在处理注销后发送SAML注销响应消息。
  5. 5.
    身份提供者将 SAML 注销响应消息发送回发送原始注销请求的依赖方。
  6. 6.
    应用程序 A 确认注销。
前面序列中的第 3 步和第 4 步通常是通过用户的浏览器发送的,使用前端通道交互。 许多 SAML 2.0 身份提供者位于企业防火墙之后,使用前端通道实现可以避免防火墙的阻隔问题。 但是,在复杂的注销场景中,如果有多个依赖方,注销流程可能会在完成之前被终止,从而导致某些会话仍然处于保持状态。 SAML 2.0 规范包括一个后端通道注销机制,如果需要将注销消息发送给多方,该机制可能更可靠。 但是,可能并非所有 SAML 2.0 实现都实现了后端通道注销,并且后端通道注销消息需要身份提供者和依赖方之间的直接连接,这对于企业防火墙后面的组件可能具有挑战性。

会话终止

有时可能需要快速终止用户的 SSO 会话以及应用程序会话。比如在公司环境中,员工被解雇的情况下的会有这样的要求。在没有单点注销的情况下,可以在身份提供者处禁用用户的帐户,但他们可能能够在具有打开会话的应用程序中保持活动状态,直到应用程序下一次与身份提供者通信。对于 OIDC 或 OAuth 2.0,结束应用的活动状态可能是在应用程序会话和/或访问令牌到期时。在 SAML 2.0 的情况下,它将是应用程序会话到期的时间。发生这种情况时,应用程序会向身份提供者发送新的身份验证请求,如果用户的帐户被禁用,该请求将失败。如果担心此类风险,则应考虑所涉及应用程序的敏感性以及快速终止用户会话的方法的可用性来设置应用程序会话持续时间和访问令牌到期时间。

注销和多级身份验证

如果基于所使用的身份验证机制的强度实施递升或多因素身份验证,用户会话可能处于不同的身份验证保证级别,则应该清楚用户注销时会发生什么。 一个常见的解决方案是注销以完全终止用户的会话,无论其处于何种身份验证级别。 无论选择何种注销行为,重要的是让用户清楚其行为。

注销后的重定向

设计注销的最后一个方面是注销后将用户重定向到哪里。 如果注销操作将用户送到一个应用程序主页,该页面恰好又将用户重定向到一个身份提供者,在那里用户仍然有一个有效的会话,那么用户将会又返回到应用程序,并为他们创建一个新的会话。 这就中断了注销过程,用户会抱怨注销不起作用 ,并可能浪费Help Desk时间, 为了获得更好的用户体验,您可以重定向到注销确认页面或并且不会自动将用户重定向到身份提供商的主页。 除了在注销后仔细选择将用户发送到哪里之外,您还应该确保重定向只针对列入白名单的 URL 列表,以避免打开重定向产生的漏洞。 为注销白名单规划适当的重定向 URL 将提供一个良好的用户体验并避免开放重定向漏洞vivii

总结&重点回顾:

实现注销的设计和测试可能比登录更复杂。 一个用户可能有多个身份验证会话,您需要决定在任何用户会话终止或超时时终止哪个会话。 除了注销行为之外,设计还应该指定在注销发生后将用户发送到哪里。我们现在已经涵盖了用户登录和注销系统时发生的所有事件。 在身份生命周期的某个时刻,用户的资料可能会发生变化,需要更新身份配置文件的属性,帐户管理可以实现这一点,这是在账户管理的章节会详细介绍这一主题。
  • 与登录相比,注销通常需要更多的时间来设计和测试。
  • 解决方案设计应指定在用户注销时应终止哪些身份验证会话。
  • 设计应指定注销后将用户重定向到何处。
  • 单点注销可用于向与用户身份提供者会话相关的依赖方会话发送注销消息。
  • 注意使用 OIDC 注销的草案规范。
  • SAML 2.0 依赖方可以发送注销请求以终止用户在身份提供商处的会话。
  • SAML 2.0 支持单点注销。
  • 任何注销的影响和范围都应向用户明确。

参考