登录工程:现代 Web 应用的典型身份验证需求

1,814 阅读13分钟

朋友就职于某大型互联网公司。前不久,在闲聊间我问他日常工作的内容,他说他所在部门只负责一件事,即用户与登录。

而他的具体工作则是为各个业务子网站提供友好的登录部件(Widget),从而统一整个网站群的登录体验,同时也能令业务开发者不用花费额外的精力去关注用户鉴权。这很有趣。

可以看出,在一个现代Web应用中,围绕“登录”这一需求,俨然已经衍生出了一个新的工程。不管是我们面临的需求,还是解决这些需求所运用的方法与工具,都已经超出了传统Web应用身份验证技术的范畴。

之前一篇文章中,我聊到传统Web应用中的身份验证技术,文章中列出的一些方法在之前很长一段时间内,为满足大量的Web应用中身份验证的需求提供了思路。在这篇文章里,我将简要介绍现代Web应用中几种典型的身份验证需求。

形式多样的鉴权

考虑这样一个场景:我们在电脑上登录了微软账号,电脑里的“邮件”应用能够自动同步邮件;我们登录Web版本的Outlook邮件服务,如果在邮件里发现了重要的工作安排,将其添加到日历中,很快电脑里的“日历”应用便能够将这些日程显示到Windows桌面上。

这个场景包含了多个鉴权过程。至少涉及了对Web版本Outlook服务的鉴权,也涉及了对离线版本的邮件应用的鉴权。要能够支持同一批用户既能够在浏览器中登录,又能够在移动端或本地应用登录(例如 Windows UWP 应用程序),就需要开发出能够为两种应用程序服务的鉴权体系。

在浏览器里,我们通常假设用户不信任浏览器,用户通过与服务器建立的临时浏览器会话完成操作。会话开始时,用户被重定向到特定页面进行登录。登录完成后,用户通过持续与服务器交互来延续临时会话的时长;一旦用户一段时间不与服务器交互,则他的会话很快就会过期(被服务器强制登出)。

在移动应用中,情况有所不同。相对来说,安装在移动设备中的应用程序更受用户信任,移动设备本身的安全性也比浏览器更好。另一方面,将用户重定向到一个网页去登录的做法,并不能提供很好的用户体验——更重要的是,用户在使用移动设备时,时间是碎片化的。我们无法要求用户必须在特定时间内完成操作,也就基本没有会话的概念:我们需要找到一种能够安全地在设备中相对持久地存储用户凭据的方法,并且Web应用服务器可能需要配合这种方式来完成鉴权。此外,移动设备也不是绝对安全的,一旦设备丢失,将给用户带来安全风险。所以需要在服务器端提供一种机制来取消已登录设备的访问权限。

(图片来自:http://docs.identityserver.io/en/release/intro/big_picture.html)

方便用户的多种登录方式

“输入用户名和密码”作为标准的登录凭据被广泛用于各种登录场景。不过,在Web应用、尤其是互联网应用中,网站运营方越来越发现使用用户名作为用户标识确实给网站提供了便利,但对用户来说却并不是那么有帮助:用户很可能会忘记自己的用户名。

用户在使用不同网站的过程中,为了不忘记用户名,只好使用相同的用户名。如果恰好在某个网站遇到了该用户名被占用的情况,他就不得不临时为这个网站拟一个新的用户名,于是这个新用户名很快就被忘记了。

在注册时,越来越多的网站要求用户提供电子邮箱地址或者手机号码,有的网站还支持让用户以多种方式登录。比如,提供一种让用户在使用了一种方式注册之后,还能绑定其他登录方式的功能。绑定完成之后,用户可以选用他喜欢的登录方式。它隐含了一个网站与用户共同的认知:联系方式的拥有者即为用户本人,这种“从属”关系能够用于证实用户的身份。当用户下次在注册新网站时遇到“邮件地址已被注册”,或者“手机号已被注册”的时候,基本可以确定自己曾经注册过这个网站了。

(图片来自:http://cargocollective.com/)

另外,登录过程中所支持的联系方式也呈现出多样性。电子邮件服务在很多场景中逐渐被形式多样的其他联系方式(比如手机、微信等)所取代,不少人根本没有使用邮件的习惯,如果网站只提供邮箱注册的途径,有时候还会遭到那些不经常使用电子邮箱的用户的反感。所以支持多种登录方式成为了很多网站的迫切需求。

双因子鉴权:增强型登录过程

上一节中提到的“从属”关系不光可以帮助用户判断自己是否注册过一个网站,也可以帮助网站在忘记密码时进行临时认证,从而帮助用户完成新密码的设置。如果将这种从属关系用于正常登录过程中的进一步验证,就构成了双因子鉴权。

双因子鉴权要求用户在登录过程中提供两种形式不同的凭据,只有两种验证都成功才能继续操作。现代化Web应用正在越来越多地使用这种增强型验证方式来保护关键操作的安全性。例如,查看和修改个人信息,以及修改登录密码等。

相信不少人还记得QQ密码保护问题的机制,它使得盗号者即使盗取了QQ密码,在不知道密码保护问题的情况下,也无法修改现有密码,让账号拥有者得以及时挽回损失。

双因子的原理在于:两种验证因子性质不一致,冒用身份者同时获得用户这两种信息的机率十分低,从而能有效地保护账号的安全。在QQ密码保护的例子里,密码是一种每次登录时都会使用的固定文本、相对容易被盗;而密码保护问题却是不怎么频繁设置和更改的、隐秘的、个人关联性极强的,不容易被盗。

(图片来自:http://bit.ly/2kFc492)

现代化Web应用形式多样,设备种类繁多,场景复杂多变,而为了更好地保护用户账号的安全,很多应用开始将双因子验证作为登录过程中的鉴权步骤。而为了兼具安全和便利的特点,一些应用还要求运用一些优化策略以提高用户体验。比如,仅在用户在新的设备上登录、一段时间未登录之后的再次登录、在不常用的地点登录、修改联系信息和密码、转移账户资产等关键操作时要求双因子鉴权。

单点登录:还是需要精心设计

以前,一般只有大型网站、向用户提供多种服务的时候(比如,网易公司运营网易门户和网易邮箱等多种服务),才会有单点登录的迫切需求。但在现代化Web系统中,无论是从业务的多元化还是从架构的服务化来考虑,对服务的划分都更细致了。

从整个企业的业务模式(例如网易门户和网易邮箱),到某项业务的具体流程(例如京东订单和京东支付),再到某个流程中的具体步骤(例如短信验证与支付扣款),“服务”这一概念越来越轻量级,于是人们不得不创造了“微服务”这个新的品类词汇来拓展认知空间。

(图片来自:http://cargocollective.com/)

在这整个的演变过程中,出于安全的需要,身份验证的需求都是一直存在的,而且粒度越来越细。以前我们更关注用户在多个子站点的统一登录体验,现在我们还需要关注用户在多个子流程中的统一登录体验,以及在多个步骤中的统一登录体验。而这些流程和步骤,很可能是独立的Web系统(微服务),也有可能是一个用户界面(独立应用),还有可能是一个第三方系统(接口集成)。

可以说,单点登录的需求有增无减,只不过当开发者对这种模式已经习以为常,不再意识到这也是一个能够专门讨论的话题。

考虑与用户系统集成,与业务系统分离

在讨论安全时,分不开的两个部分就是鉴权(Authentication)与授权(Authorization)。

鉴权的过程是向用户发起质询(Challenge),完成身份验证工作。这正是登录所解决的问题。通常在登录系统成功识别用户之后,就会将接下来的工作直接交给业务系统来完成。由于各个系统中的授权模型可能与业务形态有关系,因此登录与业务系统分离是很自然的设计。

在对安全要求更严格的企业或企业应用中,可能需要专门的访问管理机制,不过,这样的做法在互联网应用中很少见。但在互联网Web应用中,授权的范畴也包含一个很小的公有部分,是各个业务系统所共有的:即用户状态。我们希望在各业务子系统之间共享用户状态:用户被锁定之后,他在所有业务系统都被锁定;用户被注销之后,所有业务系统中有关他的数据都被封存。

(图片来自:http://cargocollective.com/)

另外在多个业务系统中,还可能会共用用户的基本资料和偏好设置等数据。比如,类似于邮件地址这样的资料,它可以作为登录凭据,也可以作为一个基本的联系方式。如果用户在一个子系统设置了偏好语言,其他子系统则直接使用该设置即可。这样,开发一个“用户”系统的想法也就应运而生了。由于与用户的状态等基础信息的关系很紧密,登录与用户系统之间的集成是很自然的,将登录子系统直接作为这个用户系统的一部分也不失为一种不错的实践。

与第三方集成:迎接更多用户

“即得”是一个开放式文档共享应用,特点是“无需登录,即传即得”,它利用长时间有效的Cookie来标识用户,从而免除了人们使用应用之前必须注册登录的繁琐步骤。

这种做法的风险是,如果用户有及时清理浏览器Cookie的习惯,那很可能导致用户再一次登录时不再被识别。不过从这样一个小例子中,却容易看出登录的真正作用,就是Web应用识别用户的过程,当下次同一个用户再次使用时,Web应用就能够知道“这就是上次来过的那个用户”。

如果识别用户这一需求能够在不需要用户注册的前提下搞定,岂不两全齐美?基于第三方身份提供方的接口来识别已经在其他平台注册的用户,并将其转化为自己应用中的用户,这种方式完全可行,并且大量的开发人员已经有了丰富的实践。

从 2010 年开始就有不少的大型互联网公司开始推出开放平台服务,让第三方应用通过Web接口与这些互联网服务交互,从而为他们提供更丰富多彩的功能。在这个过程中,一些应用不为这些平台提供扩展,却巧辟蹊径地利用了这些开放平台的身份识别接口来免除新用户注册的过程,从而为自己的产品快速导入用户。不少网站都提供“使用微博账号登录”功能,相信读者一定体验过。

(图片来自:http://bit.ly/2kFi3e8)

如果你的应用需要向第三方提供用户,那么我们的角色就由“从上下文中读取用户身份”变成了“向上下文中写入用户身份”了。如果你正好有过与各互联网公司开放平台的接口打交道的经历,这时候,你就可以体验一把提供开放、安全上下文的挑战了。如果……你的平台既希望让其他平台的用户能够平滑接入,又希望向其他平台公开自己的用户,那可能是另一番更有趣的挑战。这个过程,也可以作为生物验证之外的另一种间接消除密码的实践方式吧。

登录,现在实实在在地成为了一个独立的工程。尤其在形态多样的基于Web的应用,以及这些Web应用本身所依赖的各色后端服务快速生长的过程中,各种鉴权需求随之而来。如何在保障各个环节中安全的同时,又为用户提供良好的体验,成为一个挑战。

另外,个人信息泄露的事件频繁被曝光,它们导致的社会问题也开始被更多人关注和重视,作为IT系统支撑者的工程师们有责任了解事关安全的基础知识,并掌握必要的技能去保护用户数据和企业利益。

我会在接下来的文章中介绍解决典型登录需求的具体技术方案,以及相关领域的安全实践常识。


更多精彩洞见,请关注微信公众号:思特沃克