用户在一段时间内与应用程序的交互称为会话。Session代表浏览器与服务器的一次会话过程,这个过程是连续的,也可以时断时续的。
对应用程序进行身份验证后,用户希望在会话期间浏览应用程序并执行各种事务,而无需在每次执行某项操作时进行身份验证。为了实现这一点,应用程序需要一种跟踪用户是否已通过身份验证的方法。在打开浏览器认证完成后,服务器会自动为其创建一个Session,并赋予其一个SessionID,发送给客户端的浏览器。
以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:(Cookie:SESSIONID=客户端第一次拿到的Session ID)。这样,服务器端在接到请求时候,就会收到Session ID,并根据ID在内存中找到之前创建的Session对象。
应用程序可以跟踪有关用户是否、何时以及如何进行身份验证的数据以及在用户会话期间维护的其他信息。对于Web应用程序、单页应用程序和在设备上本机运行的应用程序(如移动应用程序),会话和会话状态的处理可能会有所不同。在本章中,我们将描述会话存在的位置、会话过期和续订会话。
应用会话
在用户会话期间,应用程序可能需要跟踪特定信息,例如飞行中的事务或会话可以持续多长时间。对于传统的web应用程序,用户的会话状态可以通过向服务器分配会话标识符并将其存储在内存、文件系统、数据库或Redis等共享服务中来维护。会话标识符可以存储在应用程序设置的cookie中,然后,浏览器将其与每个请求一起发送到应用程序服务器。当收到请求时,服务器可以使用cookie中的会话标识符来检索用户的会话信息并处理请求。有时,如果会话数据足够小,它可能全部存储在cookie中,从而消除了服务器端存储的需要。
- Web应用
传统的Web应用通常都会设置一个会话过期时间。服务器维护会话需要占用服务端的资源,而用户的习惯原因,很少有用户会主动的退出(注销会话),因而如果一直保持会话会对服务器的资源造成巨大的浪费。另外,如果长时间的保持会话,也会存在一定的风险,如果用户的客户端的会话标识泄漏会给用户带来数据泄漏的风险。因而,需要服务端设置一个会话超时的时间,如果超过一段时间没有任何的交互,那么服务端会主动的注销掉该会话。至于多长的时间,会根据业务的敏感程度不同而定。
- SPA应用
对于单页应用程序来说,通常采用无状态后端API,这时候用户不再需要服务器端会话,但由于其他原因,会话超时的概念仍然存在。用户的登录的Token仍然面临可能被劫持的影响,因此,仍然需要控制会话的时长,避免长时间打开的会话。对于处理敏感数据的应用程序、许多面向业务的应用程序以及存在共享的设备访问的应用的情形,尤其关键。当会话超时时让用户重新身份验证可以确保授权用户仍然控制设备和会话。
- Native APP
在移动设备上运行的本机应用程序还有其他注意事项。手机的屏幕和输入较PC端来说,输入用户名和口令相对复杂,如果频繁的重新验证会用户体验造成困扰。另外,因为手机具有特殊的私有属性,共享的场景较为少见,同时手机本身具有一定的登录机制。因此,手机端对于一些面向消费者的应用程序,为了消除使用障碍,一般都会让用户尽可能长时间地保持登录状态。因此,移动应用通常使用无状态API,即使用户的本机应用程序会话在较长时间内保持,都不会增加服务器端的太多的成本。敏感应用程序(如银行应用程序)通常仍在移动设备上实施会话超时,但不太敏感的本机移动应用程序可能允许会话持续较长时间,直到用户明确注销。
IDP 身份提供者的Session
基于越来越多的应用采用外部的IDP进行身份认证,不需要每个应用会话超时以后都需要分别进行一次认证。因而,身份提供者还需要为用户维护一个会话,以应多个跨应用的请求。
一种解决方案是使用会话标识符和属性(如用户标识符、使用的身份验证机制、身份验证时间以及会话何时过期)创建会话对象。身份提供者可以在用户浏览器中创建包含所有会话信息的cookie,或者只创建一个映射到服务器端会话数据存储的会话标识符。然后,浏览器将身份提供程序cookie连同每个请求一起发送给身份提供程序。当用户被重定向到身份提供程序时,它使用cookie中的数据来检测用户是否已经通过身份验证。
当用户通过认证以后,IDP设置或者更新浏览器中的Session信息,并且通过重定向返回给应用一个安全的Token。应用则可以根据Token中的信息,为该用户设置或者重置应用的Session信息。当应用给该用户的Session过期时,应用则可以向IDP重新询问该应用的登录状态。一种方式是仍然通过重定向的方式,此类请求将包括身份提供者先前设置的任何cookie,其中包含用户的会话信息。如果用户在标识提供程序处的会话仍然有效,则标识提供程序将向应用程序返回一个新的安全令牌,而不强制用户再次进行身份验证。一些身份提供者可以支持用于在身份提供者处检查用户会话状态的替代机制,这可以使应用程序在用户的身份提供者会话仍然有效时避免浏览器重定向。当然,如果身份提供程序会话已过期,并且用户需要重新验证,则需要将用户重定向到身份提供程序。
多处会话
一个用户可能在不同的解决方案组件之间有多个会话。用户可以在一个或多个应用程序中拥有会话。如果应用程序将身份验证委托给身份提供程序,则该身份提供程序可以为用户提供会话。如果应用程序将身份验证委托给身份验证代理,而身份验证代理又将身份验证委托给远程身份提供商,例如社交身份提供商或企业身份提供商,则可能存在三个架构层,其中都会存在会话。 图10-2显示了三种不同的体系结构模型以及可能存在认证会话的位置。
会话持续时间
为用户建立的每个会话可以在不同的时间因各种原因终止。除了用户主动退出会话,会话会被终止。其他情况下,如会话的时间如果超过最大的时长限制,不管用户是否活动,会话可能会被终止。用户如果长时间没有活动,会话的空闲时间超过了会话空闲时间限制,会话也会被终止。
对于空闲时长的情况,如果应用监测到用户的活动,那么空闲的计时器会被重置,意味着会话被延长了。应用会话的空闲时长会被延长,但是,并不会被IDP感知,也不会对IDP的会话空闲时长产生影响。除非通过IDP可感知的方式,如重定向的认证请求。
空闲时长保障了一定的安全性,但是也有可能会带来不要的用户体验。比如,用户当用户长期未操作,实际上应用的会话已经终止,这时用户是无感知的,他可能会在前端填写大量的数据,而这时候如果用户未被告知的情况下提交数据,填写的数据可能会被丢失,这种用户体验是非常糟糕的。因此,应用可以监测空闲时长,当因为空闲用户会话即将要终止时,给予用户提示,如果用户仍然需要继续操作,则对会话进行延期。
事实上,恰当的会话周期不仅仅保障了安全性,也和用户体验有关。不同的用户平台,不同的应用敏感度,应该设置不同的会话时长。对于空闲时长,需要考虑可以承受用户多久离开自己的桌面不操作应用的时长。显然,如果手机端应用,则不用太多考虑,正常来说手机一般由用户随身携带,且自身有认证的机制,不太会在物理上由他人来控制或使用。对于最大的会话时长,则需要考虑最长多久时间,用户需要重新认证一次,以保障用户对于自身的会话的控制仍然掌握,或者更新下最新的用户信息。
在设计这些会话的时长时需要经常考虑的问题包含,这个应用时面向消费者还是客户,应用时桌面、浏览器还是移动应用,应用的敏感程度的级别。通常我们可以按照经验去设置一个区间,通过不断的调整找到合适的、正确的设置。
会话可能因超时以外的原因而结束。用户可以显式注销。管理员可能会出于各种原因终止用户在身份提供商处的会话,例如凭证受损的报告。如果服务器重新启动,用户的会话可能会终止,也有可能用户的会话可能存在于服务器上,但用户删除了浏览器中包含会话信息的cookie,该会话也将无法恢复。我们 需要在应用程序设计中应考虑会话终止的可能性,并为每种情况定义适当的操作。
由于会话终止的方式多种多样,而且有可能存在混合使用了多个会话,关系到用户体验和安全的事情用户可以不了解背后发生了什么,但是应用程序设计人员必须了解任何会话终止时对其他会话的影响。例如,如果应用程序会话过期,它是否应该请求终止用户在身份提供商处的会话?如果用户的身份提供商会话终止,是否会触发使用同一身份提供程序的相关应用程序中的会话立即终止?如果是使用外部的身份提供者,所考虑的选项可能会受到身份提供者策略的约束,但设计者仍应列举不同会话终止场景所发生的情况。
应用程序可能希望定期检查身份提供者处用户会话的状态。这样,当身份提供者的会话结束时,应用程序可以终止自己的会话。当用户的应用程序会话超时时,也可以执行此操作,应用程序将检查用户的身份提供者会话的状态作为其自身会话续订过程的一部分。
会话更新
当用户的应用程序会话到期时,应用程序可能希望用户能够续订会话。它可以通过将用户重定向回身份提供者来实现这一点。如果用户没有有效的会话,身份提供者可以对用户进行身份验证,并根据应用程序身份验证请求中的参数将新的安全令牌返回给应用程序。如果用户的身份提供程序会话仍然有效,则用户无需重新验证,应用程序将根据用户的现有会话接收新的安全令牌。然后,应用程序可以在续订用户的应用程序会话时使用新安全令牌中的信息。
应用程序可以在身份验证请求中使用参数来抑制或强制活动身份验证。例如,如果自用户上次主动身份验证以来经过了一定的时间,则可能需要进行重新身份验证。在OIDC协议中,可以将可选的“prompt”参数添加到身份验证请求中,以强制或禁止OpenID提供者上的弹出或者禁止身份验证。可选的“max_age”参数可用于控制用户在通过认证后的最长使用时间,使用max_age的应用程序仍应检查ID令牌中的auth_time声明,以确保遵循了请求的max_age。如果OpenID提供程序具有相对较长的最大或空闲时间,但是特定应用程序希望更加频繁地进行身份验证,那么使用max_age和auth_time就会非常的实用。使用SAML2.0,应用程序可以使用身份验证请求的“ForceAuthn”属性强制身份提供程序主动对用户进行身份验证。此类身份验证请求参数为应用程序提供了一定程度的控制,以控制当用户重定向到身份提供程序时,是否对其进行主动重新身份验证。
除了通过重定向的方式,为了改善用户体验。身份提供者可以支持检查用户会话状态的替代方法。如果用户在身份提供者处具有有效会话,则允许在不需要浏览器重定向的情况下续订应用程序会话。如果用户的身份提供程序会话不再有效,则可以重定向该用户以续订身份提供程序会话。
令牌更新
除了更新会话外,应用程序可能还需要定期更新安全令牌。应用程序可能已收到ID令牌,也可能已收到用于调用API的访问令牌。应用程序可能希望定期请求新的ID令牌,以确保其对经过身份验证的用户具有最新的声明。应用程序以前请求的访问令牌已经过期,可能希望请求一个新的访问令牌,因为它需要调用一个API。在许多情况下,尤其是对于公共客户机,发行到期时间较短的访问令牌并在需要时更新令牌被认为是一种最佳做法,因此在用户会话存在的整个过程中都可能需要新令牌。
,在应用程序会话期间,根据应用程序的类型,应用程序可以使用不同的机制更新ID令牌或访问令牌。传统Web应用程序和本机应用程序可能能够获取刷新令牌以用于续订ID令牌和/或访问令牌,但是,这样做并不是必须的。使用刷新令牌续订令牌可避免中断用户体验,但是通过后端的刷新令牌请求通道请求ID或访问令牌,可能不会更新身份提供程序的会话cookie,从而导致更快的空闲超时。 作为公共客户端实现的单页应用(SPA)程序,无法安全地存储和处理刷新令牌,因此必须使用不依赖刷新令牌的方法,除非其授权服务器对刷新令牌的泄漏风险采取了安全措施(如使用刷新令牌轮换或具有使用约束条件的刷新令牌)。不依赖刷新令牌的应用程序接收刷新令牌可以在需要新令牌时将用户重定向到OpenID提供程序。如果用户具有有效会话,则应用程序将接收新令牌。如果用户没有有效会话,请求将根据需要触发身份验证和同意。即使是使用刷新令牌的应用程序,也可能希望定期使用重定向方法来更新身份提供程序的会话cookie和空闲超时。
然而,将用户重定向到OpenID提供方并返回会带来用户体验的挑战,有可能会中断用户体验。对于单页应用程序,这可能会导致用户的工作丢失,除非应用程序保存用户准备提交的数据,并在从OpenID提供方返回后恢复它。一个改进是在应用程序中使用隐藏的iframe进行重定向,并将“prompt”参数设置为“none”,以避免中断用户体验。如果用户具有有效会话,则应用程序将接收新令牌。如果没有,应用程序将收到错误响应,并且可以再次重定向用户,而无需使用“prompt=none”选项触发身份验证。OpenID提供商应在提供SDK中包含相关的设计,使应用程序更容易执行此操作。
会话重建
在频繁使用的应用程序中,如果用户在重新验证时必须重新输入多个选项,那么频繁出现会话超时可能会对用户体验造成干扰。需要会话超时且属于此类别的应用程序可能希望通过提供会话超时后可以重建的会话来提供更好的用户体验。使用此方案,在会话超时时,系统使会话失效以暂停进一步使用,但会保留会话的内存和与之相关联的标识,以便在用户主动重新验证时,会话状态可以恢复到其以前的状态。这样的会话由活动用户注销来终止和永久删除,而不是会话超时。但是,仍然需要限制会话处于休眠状态的时间,以减少向后兼容性问题,同时并避免因用户删除会话cookie等事件而造成存储了孤立的会话数据。
本章重点回顾
应用程序在用户与应用程序交互期间为用户维护会话。如果应用程序将身份验证委托给外部身份提供程序,则在解决方案体系结构的不同层上,用户可能会有多个会话。为用户维护会话的每个组件可能有一种或多种类型的会话超时。会话是实现单点登录的关键因素。