在保证安全又兼顾业务逻辑的前提下,身份认证、授权的管理其实是很复杂的,因此,很难提供一个万能的方法来实现身份管理(Identify Management)。
导言
身份管理在理论上是很简单的,但是实际需要考虑的问题很多(业务逻辑,用户体验,安全性等等),这就造成了身份管理系统实现难度很高的窘境。
举个例子,用户希望可以通过第三方认证比如微信来登录的你应用,他们甚至希望可以使用多个第三方认证(微信,QQ,微博,Facebook,Google……)都可以登录你的应用,并且使用不同的第三方账户登陆时,仍然可以将识别为是同一个人的账号。如果你不能处理好这些需求,用户可能会无情流失。再比如,企业内部用户希望使用同一账号访问多个内部系统,并且希望 SSO(single sign-on,单点登录)。并且,企业网内部长根据角色(role)给不同用户不同的访问权限。
- 一些敏感内容可能需要比简单密码更加强大的认证方式;
- 不同的平台需要提供不同的用户体验:在 Web 上,用户可能期望跳转到登录页面进行身份认证;但是原生桌面程序的用户可能希望跳出会话框来进行认证;
目标
本文以及后续系列文章的目的是为读者提供关于身份管理的介绍,包括:账户创建,认证,API 授权,SSO 单点登录,用户登出等。本系列将会涵盖OAuth 2.0, OIDS 以及 SAML 2.0 等协议。
术语
- identifier(标识符):在特定上下文中,用来唯一标识一个实体的属性。比如,邮件地址,驾照号码,员工号码等。
- identity(身份):用来表示在特定上下文中,与一个实体关联的属性的集合。一个 identity 可以包含一个或多个 identifier,同时也可以包含除 identifier 之外的其他属性。比如一个名为 human 的 identity 可以包含 身份证号码,驾照号码,性别,国籍等属性,但是只有身份证号码和驾照号码可以作为 identifier。
- account(账户):在特定上下文或应用程序中的一个 local construct。identifier 可能存储在 account 中,也可能处处在其他地方并被 account 引用。一个 account 还可能有自己的 identifier。account identifier 与 identity 的分离也是有好处的,方便 identity 的复用。
我们对包含多个 identifier 属性的实体使用“identify”术语,把关联一个或多个 identity 的结构称为“account”。
身份管理(Identity Management, IdM)系统就是一组服务,用以支持创建、修改和删除身份以及关联账户,以及访问资源所需的身份验证和授权。
一个身份的生命周期中的事件(event)
- provisioning
- 包括创建账户以及管理的identity(包括为 identity 分配一个独一无二的 identifier)
- authorization
- 授予权限,告知账户可以做什么
- authentication
- 为了访问非公开资源.
- access policy enforcement
- 当一个用户被授权后,保证访问策略使用户能根据授予的权限访问授权的资源而不越界是很重要的。
- sessions
- 一些应用程序,通常是 web 程序,会在用户认证登陆后的一定时间内使用户身份保持有效,超出规定时间后,需要重新认证。这就是用 session 来实现的。
- single sign-on
- 单点登录SSO是用来实现一次登录之后可以访问其他被保护的资源或应用,而无需再次登录。
- stronger authentication
- 逐步身份验证(step-on authentication):指的是通过将现有的身份认证会话通过更强的身份认证方式提升级别的行为。
- 多因素身份验证(multi-factor authentication):需要提供多个要素进行验证,比如密码+指纹等
- logout
- 通过注销(log out)终止会话。
- 在 SSO 的情况下,可能需要终止多个会话。当退出一个程序时,哪些会话被终止取决于后台设计者的决策策略。
- account management and recovery
- 在标识的生命周期内,可能需要更改标识的用户配置文件的各种属性。例如,用户可能需要更新他们的电子邮件地址或电话号码。在公司中,用户的配置文件可能会被更新,以反映新的职位、地址或特权,比如角色。帐户管理由功能或过程组成,这些功能或过程使用户和管理员能够查看和更新与标识关联的用户概要属性。
- 用户也可能忘记密码或丢失验证过程中需要的设备。如果发生这种情况,用户需要建立新的凭据。在允许用户设置新的凭据之前,这需要另一种方法来建立用户的帐户所有权。帐户恢复是一种机制,通过一些辅助手段验证用户是帐户的合法所有者,然后允许用户建立新的凭据。
- deprovisioning
- 完全删除或者终止账户以及其关联的 identify 信息
identity 进化史
有关身份认证和管理的技术一直在不断发展,以应对新的安全挑战。接下来,本文会列出每种身份管理、认证等方式的优缺点。
Per-application identity
在上古时代,每个应用程序都自己实现身份存储、身份验证和授权等行为。企业可能有若干个核心应用,每个应用都有自己的数据库或存储来保存用户身份、证书或用户配置文件等数据。这意味着每个职员都需要记住每个应用的用户名和密码,这也意味着,如果某个职员的配置文件数据有变化(比如职位、部门等的变化),那么需要在所有的应用中进行修改。这就可能造成应用的数据在某段时间内是不一致的。
这种方式在今天依然有一些应用场景,比如用户通过用户名和密码登陆程序等场景。如果用户在多个站点使用相同的密码,那么任何一个站点的密码泄露都会使用户在其它站点的数据处于危险之中。如果为每个站点都使用不同的密码,那么用户需要记住越来越多的用户名和密码,这太恶心了……
Centralized user repository 中心化的用户存储库
随着时间的推移,越来越多的软件被用户更为广泛的业务。鉴于此,很多公司推出了目录服务(Directory Service)来集中的存储用户数据和身份凭证。Directory service 针对频繁读取但是很少修改的信息做了优化,用户身份数据恰好符合这个特性。程序可以使用 directory service 保存用户数据和凭证(credential),也可以根据directory service 中保存的信息验证用户输入的凭证。
中心化的身份管理以及 directory service 控制访问的方式有很多优点。首先,目录复制功能使托管在世界各地的程序可以使用相同的标识信息,消除了数据不一致的问题。同时,中心化的 directory service 提供了一个单一的控制点,可以方便地进行身份的管理。
当然,它也有一些缺点。directory service 本身并不负责维护 session。Directory service 意味着一个用户可以为多个程序使用相同的用户名和密码(存储在 directory service 中),但是用户依然需要为每个应用程序输入用户名和密码以便验证。除了不方便,这还将用户的密码暴露给了应用程序,应用程序本身可能会泄露这些敏感信息,从而使其他程序也处于危险之中。
Early SSO services
利用 identity and access management (IAM) 和 SSO Server 可以解决上述问题。
早期的 SSO server 借助保存在 directory service 中的身份信息,在 directory service 之上提供了一个维持 session 的层来记忆那些已经验证过的用户。不同的 SSO Server 工作方式可能有所区别,但是在典型的实现中,程序将用户重定向到 SSO 服务器,并在那里对用户身份进行验证,并以一种安全的方式接受验证结果。如果用户在一段合法的时间内(session 过期前)访问另一个程序,第二个程序也会将用户重定向到SSO 服务器,SSO 服务器将会检测到用户现有的 session,并返回认证结果而无需用户再次提供凭证。
与 directory service 相比,SSO 的优点是:用户只将密码暴露给 SSO server,而不会暴露给每个应用程序,同时也可以使用单一身份访问多个程序。
然而,早期的 SSO 服务器在实践中也有一些缺点。应用程序和 SSO server 之间的交互某种程度上是高度定制化的,并且 SSO 的实现是一件费时费力的事。这意味着大公司才有能力使用。另一个限制是 SSO 依赖cookie,由于浏览器对 cookie 的限制,SSO 只能在同一个 域下才能工作。随着许多公司对SaaS(Software-as-a-Service) 感兴趣,这个限制是很令人恼火的。
Federated Identity and SAML 2.0
SaaS 给身份管理带来了新的挑战。各个业务团队可能开始使用 SaaS,但是公司很难追踪员工在 SaaS 中创建的账户,现在,用户有需要记住每个应用的密码了…… 内部应用的 SSO 无法扩展到外部的 SaaS 应用。
幸运的是,2005 年发布了 SAML 2.0 (Security Assertion Markup Language)标准。它提供了跨域和联盟身份(federated identity)的 web SSO。使用 SAML 2.0,SaaS 应用可以将企业用户重定向到企业身份验证服务(也被称为 identity provider, IdP)。身份联盟(Identity Federation)提供了一种链接应用中用户身份和身份提供者的方法。公司现在可以在内部和外部的 SaaS 都使用 SSO 了。
然而,尽管SAML 2.0被广泛采用,但它并不是灵丹妙药。该协议被设计为覆盖多场景,因此配置和实现非常复杂。虽然SAML 2.0在企业环境中得到了广泛采用,但没有可行的业务模型来解决面向消费者的场景。用户不太可能为面向消费者的身份服务付费。另一个限制是SAML 2.0只解决了身份验证问题。应用程序正在演变为基于 API 的架构。SAML 2.0解决了用户身份验证问题,但对API授权没有帮助。
WS-FED
与 SAML 2.0 类似。WS-FED(Web Services Federation Language)联盟在2009年发布了 WS-FED 1.2 规范,提供了“为在域中管理的安全实体(security principal)访问在另一个域中管理的资源的访问授权”机制,并提供了与 SAML 2.0 单点登录、federated identity 类似的功能。已被微软 ADFS Active Directory Federation Services | Microsoft Docs 等支持,并广泛应用在企业环境中。
OpenID
值得一提的是最初的 OpenID 协议。SAML 2.0 仅面向企业员工,消费者用户依然需要在每个面向消费者的网站注册。OpenID 协议正是为了解决这一问题。除了向 SAML 2.0 和 WS-FED 一样支持企业控制的身份验证服务,OpenID 还支持消费级用户的中心化身份验证,消费用户可以设置自己的身份验证服务提供商。最初的 OpenID 协议没有得到广泛应用,但为之后的 OpenID Connect 协议奠定了基础。
OAuth 2.0
随着 Web 2.0 和社交媒体的发展,许多面向消费者的网站应运而生。比如允许用户分享图片的社交媒体网站。这就产生了需要代表用户访问网站的需求,比如一个打印图片的网站可以访问用户在另一个分享图片的网站的图片。如果没有好的方案,用户将不得不与图片打印网站分享他们的社交媒体的证书,如果图片打印网站遭到黑客攻击,用户的社交媒体账户将面临风险。
OAtuh 协议为这种场景提供了解决方案。OAuth 2.0 协议允许用户授权另一个应用(通常称为客户端,client)向资源服务器(server,上例中的社交媒体网站)的 API 发送请求,以代表用户得到服务器的用户数据。为了实现此行为,client 与授权服务器交互,授权服务器会授权 client 必要的访问权限。client 会收到一个 token,使用此 token 可以访问服务器资源(用户数据)。OAuth 2.0 解决了 API 授权的问题。
但是 OAuth 2.0 没有被设计为一种通用的身份验证协议,因此需要下面的 OIDC 协议。
OpenID Connect (OIDC)
OIDC 被设计为提供身份认证服务。OAuth 2.0 虽然也可以验证用户身份,但是它没有提供将经过验证的身份信息安全传递给 client 的标准方法。OIDC 正式为了解决之一缺陷而诞生的。OIDC 架构在 OAuth 2.0 协议之上,以标准格式向 client 提供已验证的账户的身份信息。这可以同时用于 API 授权和身份认证。
OIDC 为用户,应用程序和身份验证服务提供了便利。网站开发者可以将身份验证、密码重置等逻辑委托给 OIDC 提供商。用户可以实现单点登录,更加方便。OIDC 提供商如果能吸引更多的用户,其自身自然能有更多的利润。
标准化协议
为什么要使用行业标准协议?
首先,作为开放标准,这些协议已经被很多人仔细检查过了,所以比起你自己发明的东西,它们不太可能有漏洞。其次,这些协议被广泛使用,提供了您的应用程序和支持这些协议的服务提供者之间的互操作性。第三,如果您希望从谷歌等服务访问用户配置文件数据,则必须使用这些服务实现的标准协议。类似地,如果您的应用程序将被企业使用,企业可能希望您的应用程序使用这些协议之一。第四,为认证而设计的协议支持单点登录,为用户提供了方便。最后,使用现有的协议可以节省您的时间,因为许多编程语言提供支持它们的sdk。因此,您有五个使用行业标准身份协议的好理由!
如果您是身份领域的新手,最初可能会觉得学习这些协议有点困难,并且可能会想发明自己的更简单的身份验证方案。但是永远不要!