本文最初发布于 devever.net 网站,经原作者授权由 InfoQ 中文站翻译并分享。
现在,身份验证协议的数量快赶上应用程序协议,结果,这个领域很容易让人困惑。
最容易把人搞糊涂的是,很少有人注意到这样一种事实:
存在许多不同种类的身份验证协议,它们还试图扮演完全不同的角色。
与往常一样,首先请记住,身份验证和授权是不一样的功能。考虑到这一点,本质上存在三种不同的身份验证协议类别:
客户端到应用程序(客户端身份验证协议)
应用程序到验证服务器(后端身份验证协议)
单点登录(客户端到验证服务器到多个应用程序)
客户端到应用程序的身份验证协议由客户端发送给应用程序服务器进行身份验证。这种协议完全不揭示应用程序服务器在幕后如何使用客户端提供的信息对其进行身份验证。
应用程序到验证服务器的协议被应用程序服务器用来将客户端的身份验证委托给某个服务器,该客户端已使用客户端到应用程序的协议提供了信息,而验证服务器可以更好地执行身份验证决策。这种协议允许将身份验证处理外包给专门的身份验证服务器,并且无需让身份验证数据库对所有应用程序服务器都开放访问权限。
客户端的身份验证状态(例如通过客户端到应用程序的协议)通过单点登录服务器验证后,一台服务器使用单点登录协议与另一台服务器通信。换句话说,它们被用来传递身份验证决策。客户端先前成功通过验证服务器的身份验证的事实,可以在该客户端和应用程序服务器之间安全地传输。某些协议不需要进一步干预或需要单点登录服务器可用,即可允许客户端在初始登录后对应用程序进行身份验证,而其他协议则需要。
单点登录协议实际上包含两个协议:“客户端到验证服务器”部分和“客户端到应用程序”部分。客户端到验证服务器部分可能是定制的,有时可能是非常普通的客户端到应用程序的身份验证协议。而客户端到应用程序部分必须取决于 SSO 协议的设计。
客户端到应用程序协议
在客户端到应用程序验证协议的范畴内,存在验证框架和验证方法。验证框架是一种可扩展的框架,它允许实施任意多种验证方法,并允许它在客户端和应用程序服务器之间动态协商使用哪种验证方法。
一些身份验证框架已集成到特定的应用程序协议中。还有一些通用设计旨在被集成到任意多个应用协议中。这样甚至将来出现的应用程序协议也可以利用框架中已经定义的所有身份验证方法,以及这些方法的库实现。
客户端到应用程序的身份验证框架:SASL
这类框架中可能最流行的是 IETF 的 SASL。SASL 没有定义特定的有线编码(这部分由应用程序负责),而是从本质上定义了身份验证方法名称(例如 PLAIN、LOGIN、MD5 等)的名称空间,以及协商它们的过程。实际的方法特定协议已经执行,但是应用程序协议仅需要促成不透明二进制字符串序列的来回交换,直到身份验证成功或失败为止。
简而言之,实现 SASL 的应用程序协议仅需要提供以下机制:
服务器将支持的方法名称(字符串)列表发送到客户端的一种途径
客户端发送其要使用的方法名称的途径
客户端将不透明的二进制字符串发送到选定的SASL方法的一种途径(可以由应用程序服务器不透明地输入到SASL库中)
服务器的SASL库将不透明的二进制字符串发送到客户端的一种途径(可以不透明地反馈回客户端的SASL库)
验证成功或失败的一种通信途径
如何提供这些机制取决于应用程序协议,该协议必须定义一些适当的有线协议。尽管特定的编组和状态机是特定于应用程序协议的,但是 SASL 方法本身就足够独立于应用程序协议,因此实现各种 SASL 方法的通用 SASL 库被广泛采用。
一些最受欢迎的 SASL 方法是:
PLAIN,以明文形式提供身份验证用户名和密码(以及可选的授权用户名,可能与身份验证用户名不同);
LOGIN,弃用的方法,它是提供纯文本用户名和密码的另一种方法;
EXTERNAL,使客户端完全不提供任何信息(可选的授权用户名除外),并且是客户端从连接上下文请求对其进行身份验证的一种方式。例如,如果连接使用带有客户端证书的TLS,并且客户端证书足以满足身份验证的目的,则可以使用此方法进行身份验证;或者也能用于仅通过客户端IP地址对其进行身份验证的情况;
ANONYMOUS,请求未经身份验证的访问;
CRAM-MD5和DIGEST-MD5是质询响应身份验证方案,它们试图避免传输未经加密的密码;
NTLM,Windows NT LAN Manager身份验证机制;
GSSAPI,是指主要用于促成Kerberos身份验证的API(参见下文)。
如今,人们通常会使用 SASL 方法(例如 PLAIN 或 LOGIN),这些方法通过安全通道(例如 TLS)以明文形式传输密码。
客户端到应用程序的身份验证框架:HTTP
HTTP 定义自己的身份验证框架,并具有自己的方法集。可以说,HTTP 避免 SASL 的原因在于其无状态性和 SASL 不太相称。由于 HTTP 设计的运行机制是让客户端发送单个请求块,然后由服务器发送单个响应,因此 HTTP 协议不适用于 SASL 设想的身份验证完成之前的来回数据交换。
此外,对于每个请求都必须重复这种交换。
服务器通过发送一个 401 Authorization Required 错误,和 WWW-Authenticate 标头来请求身份验证以访问资源。该标头包含:
所需的身份验证方法;
“域名称”,提供对身份验证域的描述;
必须为给定方法指定的其他参数。与SASL不同,一般来说一台给定服务器只有一个方法(虽说HTTP RFC确实允许服务器通过发送多个WWW- Authenticate标头来支持多个方法,每个方法一个标头,但这种情况很少见)。然后,客户端使用包含相同方法名称和方法特定身份验证数据的Authorization标头重新发出其请求。(请注意,HTTP使用术语authorization-授权,而不是authentication-身份验证。)
一些常见的 HTTP 身份验证方法有:
Basic(基本),以纯文本形式指定用户名和密码;
Digest(摘要),指定一个用户名并以质询-响应模式哈希密码;
Negotiate(协商),允许使用GSSAPI,并实质上在HTTP身份验证内称为SPNEGO的GSSAPI之上,重新实现了SASL风格的方法协商模式。因为它涉及来回交换,所以可能需要多个请求,直到身份验证成功为止。Windows通常将“Negotiate/SPNEGO”用于NTLM或Kerberos身份验证。
客户端到应用程序的身份验证框架:SSH
SSH 还使用一组可扩展的方法定义了自己的身份验证框架。最常用的方法有:
keyboard-interactive(交互式键盘),通过任意终端提示登录;
public-key(公钥),客户端证明其握有指定私钥;
gssapi,通过Kerberos登录(参见下文)。
客户端到应用程序的身份验证方法:策略
客户端到应用程序的身份验证方法通常可以分为几个基本的类别:
完全遵循上下文身份验证(例如TLS客户端证书或IP地址身份验证)(例如SASL EXTERNAL)。
以明文形式发送用户名和密码,其中安全性(如果有的话)由封装的安全通道提供,并且在任何情况下,应用程序服务器最终以明文形式获得密码(例如SASL PLAIN;HTTP Basic;SSH keyboard- interactive)。
质询-响应方案,其中服务器发出质询随机数,客户端将密码哈希或其他构造应用于随机数和密码来响应质询(例如SASL CRAM-MD5)。
如今这些策略都已经过时了,首先是由于人们常结合使用 TLS 与纯文本传输,其次是因为它们倾向于避免以哈希形式在服务器上存储密码,或者要求以与验证方案相关的特定方式对密码进行哈希处理。这样的话,密码哈希方法就会和身份验证方法高度耦合。
非对称密码方案,其中客户端在不传输私钥的情况下证明其拥有私钥(例如SSH public-key;TLS客户端证书)。
Shared-secret(共享秘密)方案,例如TLS-PSK。
零知识证明方案,例如SRP。这些加密方式整洁但很少使用,并且还是会将身份验证协议与服务器上哈希密码的方法紧密耦合。
单点登录协议的客户端到应用程序部分。
应用程序到身份验证服务器
另一类身份验证协议与客户端到应用程序的身份验证协议完全无关,而是应用程序到身份验证服务器的协议,或称后端协议。后端验证协议是在应用程序服务器和验证服务器之间使用的(而不是在要验证的实体和对其进行验证的实体之间做一个协议),以便验证客户端提供的验证细节。
这些协议经常用于网络访问场景中,其中“应用程序”服务器是网络设备,如路由器、交换机或 Wi-Fi 接入点。由于我们不希望网络中的每个 Wi-Fi 接入点都保留身份验证数据库的副本,因此后端协议允许将身份验证决策外包给一个中心化授权源。因此,后端协议必须与某种客户端到应用程序的身份验证协议结合使用:在客户端和应用程序之间使用客户端到应用程序协议,在应用程序和身份验证服务器之间使用后端协议。
流行的后端身份验证协议包括 RADIUS 及其后继者 DIAMETER,它们主要用于网络访问场景(例如拨号 Internet 身份验证、Wi-Fi 身份验证等)。由于这些协议原本设计用于支持网络访问场景,它们都属于“AAA”(同时支持身份验证、授权、计费)协议。例如,如果需要,它们的计费功能可对拨号 Internet 连接进行基于时间和使用量的准确计费。
尽管 LDAP 不是为后端身份验证协议设计的,但它有时也被当成身份验证协议来用。应用程序服务器可以尝试向 LDAP 服务器进行身份验证来验证用户凭据。这种方法还有一个优点是,如果成功,则应用程序服务器还可以使用 LDAP 检索有关用户的信息。
应用程序到身份验证服务器:关联的客户端到应用程序协议
RADIUS 和 DIAMETER 这样用于网络访问场景的后端验证协议,传统上设计用于和特定的客户端到应用程序验证协议结合使用,比如由 PPP 定义的那些。PPP 是一个 OSI 第 2 层协议,支持通过串行线路和拨号调制解调器发起 IP 网络连接。PPP 定义了自己的可扩展身份验证框架,并支持以下方法:
PAP,以明文形式传输用户名和密码;
CHAP,一种质询响应方法(避免以明文形式传输密码,但存在前文所述的质询响应方法的缺点);
MS-CHAP和MS-CHAPv2,CHAP的Microsoft变体;
EAP,可扩展身份验证协议,现代的首选协议。
EAP 本身是一个身份验证框架,定义了一组可扩展的身份验证方法,这意味着与 PPP 一起使用时,方法协商分为两个级别:首先要协商 EAP,然后必须协商一个特定的 EAP 方法。人们认为 EAP 与其他 PPP 身份验证协议不同,前者设计同时用于 PPP 和其他网络访问上下文(例如 Wi-Fi 身份验证或以太网 802.1x 身份验证)。(802.1x 是对以太网的扩展,可以根据成功的 EAP 身份验证来确定网络访问权限)。
EAP 和 SASL 之间有一些相似之处,因为它们都是支持可扩展方法集的通用框架。但是,EAP 定义了一个特定的有线协议,而 SASL 没有定义。此外,EAP 旨在支持网络访问应用程序,而 SASL 旨在支持应用程序级别的身份验证应用程序。
但是,关于 EAP 的最重要的一点是,它从一开始就被设计为可被应用程序服务器不透明地经隧道传输。例如,假设你通过调制解调器拨入路由器,并建立 PPP 连接。路由器必须了解协议(例如 PAP 或 CHAP),并且知道如何通过 RADIUS 或 DIAMETER 与后端服务器交互协议。
在现代应用程序中,例如 Wi-Fi 客户端对一个 WLAN 接入点发送 EAP,接入点只会将 EAP 消息作为不透明数据,然后将其在 RADIUS 或 DIAMETER 会话中通过隧道传输到一个网络身份验证服务器上,让网络身份验证服务器来处理 EAP 消息。身份验证服务器同样可以返回封装在 RADIUS 或 DIAMETER 会话中的 EAP 消息,Wi-Fi 接入点将其解包并传递给客户端。这样,网络设备就与所使用的身份验证方法无关,并且不需要升级就能支持新的身份验证方法。只有验证服务器和客户端需要升级。
请注意,客户端永远不会发送 RADIUS 或 DIAMETER。RADIUS 和 DIAMETER 是严格的后端协议。因为 EAP 消息始终在转发到身份验证服务器之前被封装在 RADIUS 或 DIAMETER 消息中(身份验证客户端无法控制的进程),所以 RADIUS 或 DIAMETER 消息可以包括与 EAP 无关的,身份验证服务器感兴趣的客户端信息消息本身。例如,如果客户端正在为启用 802.1x 的以太网端口发起验证,则交换机可以包含关于客户端连接到哪个端口的信息,并且身份验证服务器可以预见它在这上面的决策。
单点登录协议
现在,我们讨论最复杂,最有趣的身份验证协议:单点登录协议。如前所述,单点登录协议必须包括两个部分:用于验证客户端到验证服务器的协议,以及用于验证客户端到任意应用程序服务器的协议。前者可能是标准的客户端到应用程序协议,也可能是定制的协议。而 SSO 协议的性质要求后者是 SSO 协议所特有的,并且是任何 SSO 协议的核心。
单点登录协议:非 Web
SSO 协议可以大致分为 Web 和非 Web SSO 协议。最受欢迎的非 Web SSO 协议是 Kerberos。
Kerberos 允许客户端使用定制的身份验证协议向身份验证服务器发起身份验证;客户端会收到一个票证,该票证能以密码方式向应用程序服务器发起身份验证,而无需与 Kerberos 身份验证服务器之间进一步的通信(验证服务器在用户登录后可能会关闭,并且不会立即让所有应用程序无法访问)。
该协议还支持客户端来验证服务器,以及服务器来验证客户端。如今,*nix 和 Windows Active Directory 环境都使用 Kerberos。对于客户端到应用程序的身份验证,通常不直接在身份验证框架内将其实现为身份验证方法。
相反,它通常是通过 GSSAPI 调用的,并且是主要的用法,例如 SASL GSSAPI 方法、HTTP Negotiate(GSSAPI)身份验证方法和 SSH GSSAPI 身份验证方法。
有趣的是,Kerberos 的当前版本 Kerberos 5 于 1993 年发布,因此仅依赖对称加密,避免了对非对称加密的依赖。如果 Kerberos 是今天设计的,则它可能会使用公钥加密,并且对中心化身份验证服务器的依赖会稍少一些。
不幸的是,Web 的极速增长看来已经侵蚀了所有非 web 协议(无论是身份验证还是其他用途)的发展空间。(但 Kerberos 5 仍然是安全的。)
单点登录协议:Web
对于 Web SSO 协议,客户端到身份验证服务器协议一直是标准的 Web 形式,也就是表单-cookies 形式。客户端到应用程序服务器的身份验证协议却很特殊。
通常,当应用程序服务器希望对客户端进行身份验证时,它将通过 HTTP 重定向将客户端引向 SSO 身份验证服务器。如果客户端尚未通过中心化验证,则会要求它进行验证;否则,如果客户端已经完成单点登录,则流程将继续进行而无需用户干预。
在对用户完成身份验证之后,身份验证服务器会通过另一个 HTTP 重定向将客户端引回到应用程序服务器。返回请求包含从身份验证服务器传输到应用程序服务器的身份验证信息,以建立客户端的凭据。该数据本身将以某种方式进行身份验证,以防止客户端对其修改。由于信息从身份验证服务器到应用程序服务器的传递是通过客户端进行的,因此客户端就像是携带花粉的蜜蜂。在某些 SSO 实现中,应用程序服务器可以直接回调身份验证服务器,以验证它已通过客户端接收到的信息。在其他 SSO 实现中,通过客户端从身份验证服务器传递到应用程序服务器的信息是加密保护的,不需要进一步验证。
应当注意,上文不是对特定 SSO 协议的描述,而是对所有常用技术的概括。由于 Web 应用程序仅需要符合标准的 Web 浏览器,因此对在 Web 平台之上实现的协议进行标准化的要求较少,于是出现了许多专有的 Web SSO 实现。
但一些标准还是出现了。今天流行的标准有:
SAML2,安全性断言标记语言第2版,一种XML的误用,用于表达加密签名语句,语句中包含受验证方和验证用途的信息,并在域之间传递此类语句。它很流行,受AWS for SSO支持。
OAuth,一种基于HTTP的协议,用于促成网站之间的授权流。它侧重于授权而非验证,但是现在也经常用于验证,尤其是与OpenID Connect扩展一起使用时。它很流行,受AWS for SSO支持。OpenID Connect扩展添加了身份验证功能,并允许在身份验证期间将用户信息(例如电子邮件地址等)传递到网站。(请注意,OpenID Connect是一种位于OAuth之上的技术,与OpenID 2没有任何关系。)
曾经被广泛采用,但现在已经过时的协议包括:
OpenID2,一种Web SSO协议,它使人们可以验证对特定URL的控制。(请注意,这与基于OAuth构建的OpenID Connect无关,两者适用的用例差异巨大。)
LID,一种Web SSO协议,与OpenID 2类似,是OpenID 2的同期竞争对手,但是不太流行。
本地 API
最后我们讨论一些系统本地身份验证 API。这些不是协议,但与协议关系很近。
PAM
PAM(可插入身份验证模块)是 nix 领域中本地身份验证的事实标准。它在 Linux 上普遍用于本地身份验证,并且在其他 nix 操作系统上也很流行。PAM 提供了基于插件的身份验证功能;PAM 插件是动态链接库,可以在运行时加载以提供任意身份验证逻辑。使用何种 PAM 插件由系统配置确定,因此可以根据需要重新配置 PAM。
尽管 PAM 具有高度可扩展性,但它被设计为支持终端交互式登录应用程序,因此受到了限制。PAM 模块向用户提交一系列零个或多个交互式提示(例如“Password:”),因此不能支持 Kerberos 那样的 SSO 身份验证方法(尽管有的 PAM 模块可以提示用户输入 Kerberos 密码并执行初始 Kerberos 登录)。
虽然 PAM 主要是为了支持终端交互式登录而设计的,但将 PAM 用作某些应用程序协议的后端(例如,用作 SASL PLAIN 的后端)也是可行且普遍的。但是,这要求应用程序服务器理解(或正确猜测)PAM 模块发出的线路提示的语义。例如,Dovecot IMAP 服务器假定,如果 PAM 模块要求输入没有字符回显的行,则说明它要求输入密码;如果该模块要求输入一行启用了字符回显的内容,则它是在要求用户名。因此,虽然 PAM 模块可以被编写为支持通过 TOTP 硬件密钥进行身份验证,并在终端上提示输入六位数的值,但非终端应用程序(例如 SASL 应用程序)无法支持它,除非专门设计为支持这种模块的提示。
GSSAPI
GSSAPI 是另一个本地 API,具有正式标准。它设计用于网络应用程序(而不是终端交互),并且最常用于通过 Kerberos SSO 启用身份验证。实际上,尽管它是旨在扩展到任意身份验证方案的通用 API,但它几乎只被用于 Kerberos、SPNEGO 和 NTLM 应用程序。可以通过 SASL GSSAPI 方法,通过任何 SASL 应用程序使用 GSSAPI。
原文链接:
评论