我的好朋友 Nico Williams 认为 HTTP 是新的 TCP,而 TCP 是新的 IP。如果是这样,那么本文的其余部分可能不值得阅读。然而,并非每个应用程序——特别是在发展缓慢的企业界——都会在一夜之间迁移到 Web,即使离线 Web 应用程序不断改进,我们中的一些人仍然更喜欢我们的厚客户端邮件阅读器,以及其他一些东西。此外,SSH 等远程登录协议以及 CIFS 和 NFS 等文件共享协议并不总是具有直接的 Web 等效项。
现在,Mozilla Persona 解决了一系列有趣的身份验证问题:它具有公钥基础设施的最佳特性(特别是,服务器不需要与身份提供者共享密钥),而没有其中的一些缺点(因为证书是短暂的,吊销问题变得不那么重要)。Persona 的另一个非常好的特性是它不需要您以特定方式进行初始身份验证——可以使用密码、一次性密码、智能卡、PKIX 证书、Kerberos 票据、EAP,或者上述方法的某种组合——只要您的身份提供者知道您是谁并且可以颁发 Persona 证书,您就可以开始了。
因此,人们可能会想:我们能否将 Persona 的优势引入非 Web 应用程序?我们可以。在非 Web 世界中,许多网络协议使用简单身份验证和安全层 (SASL) 或通用安全服务应用程序编程接口 (GSS-API) 来抽象身份验证。我们将略过这些细节,只需说,作为应用程序在其自身协议内交换任意数量的消息的回报,服务器能够对客户端进行身份验证(并且可能反之亦然)。还可能存在一个共享密钥,可用于加密或签名后续流量。
可以使用 SASL 或 GSS-API 进行身份验证的协议包括IMAP、SMTP、XMPP、LDAP、CIFS、NFS、SSH 甚至HTTP 本身等首字母缩略词组合。因此,如果我们为 SASL 和 GSS-API 配置 Persona,我们就可以使用 Persona 身份(即经过验证的电子邮件地址或类似地址)在任何这些应用程序协议中进行身份验证。
这正是我们一直在努力的方向。我和 Nico 编写了一个互联网草案,该草案将 BrowserID 作为 SASL 和 GSS-API 安全机制进行了配置(我们使用“BrowserID”来指代实际的协议)。我的公司PADL 开发了一个开源实现,该实现可在 Github 上获得。(我们还为 Windows 制作了一个安全支持提供程序原型,它使 Outlook、Exchange 和 Internet Explorer 等应用程序能够与 Persona 协同工作。插入:我们正在与我们的合作伙伴 Painless Security 合作探索该产品的商业可能性。)
在本文的其余部分,我们将了解非 Web 应用的 Persona 与正常的基于 Web 的身份验证有何不同,并展示一个示例,演示如何使用 Apple Mail 客户端从 IMAP 服务器登录 Persona。
Persona 回顾
关于 Persona 的工作原理有很多文章,但为了方便起见,我们将在本文中回顾一下该协议。Persona 是一种联合的、分散的身份验证协议。用户使用浏览器登录到身份提供者 (IdP),IdP 是可以验证其电子邮件地址的实体,尽管它可以是任何类似于电子邮件地址的可验证地址。
当尝试向服务器(称为依赖方或 RP)进行身份验证时,浏览器会生成一对私钥/公钥,并要求 IdP 颁发一个证明公钥的证书。(这些证书可能会被缓存。)然后,浏览器会生成一个断言,其中包含 RP URL 和时间戳,并使用用户的私钥对其进行签名。浏览器将此断言和用户的证书提供给 Web 服务器,Web 服务器验证 URL 和时间戳,并使用用户和 IdP 的公钥对用户进行身份验证。
有关 Persona 的更多信息,请参见Mozilla Persona 网站。本博客中也曾对此进行过介绍,例如Persona Beta 2 发布和第一个 Persona 发布帖子。
扩展到非 Web 应用
最简单地说,将 Persona 用于非 Web 应用与 Web 应用的情况相同,只是断言包含服务主体名称而不是 HTTPS URL。服务主体名称是从 Kerberos 继承的构造,用于标识在特定主机上运行的服务(例如,“imap”或“xmpp”)。(它们还可以标识在主机上运行的服务的特定实例。)例如,mail.example.com 上的 IMAP 服务器的服务主体名称将为“imap/mail.example.com”。因为 Persona 受众必须是 URL,所以我们将服务主体名称封装在 URN 中。
我们没有说明应用程序如何将断言发送到服务器,因为 SASL 和 GSS-API 抽象都没有说明这一点。这是应用程序协议的事情:通常,它在自己的协议中会有一条特定的消息,可以封装身份验证令牌(例如,在 IMAP 中,这是“AUTHENTICATE”消息)。我们只说明应用程序必须允许用户登录其 IdP 并生成断言,这意味着它们必须能够运行嵌入式 Web 浏览器。大多数操作系统都提供用于新安全机制的插件接口,因此通常是可能的。
到目前为止,这非常简单:弹出一个 Web 浏览器控件,使用一个看起来有点奇怪的 URL 来标识服务器,获取一个断言并将其发送到服务器。服务器验证断言,像往常一样识别用户,一切正常。实际上,这几乎就是协议;这证明了 Persona 设计人员的才能,因为它可以如此轻松地被重新利用。
但是,我们进行了一些小的调整,使 Persona 对于非 Web 应用更有用。我们在下面描述这些调整。
重放检测
Persona 规范没有说明将断言重放到服务器是否安全。我们有点偏执,特别是因为我们不知道应用程序是否正在使用 SSL/TLS 等传输安全。因此,我们在协议中内置了重放检测。这可以通过以下两种方式实现:服务器在特定时间范围内维护已接收断言的缓存,或者客户端对服务器生成的随机数进行加密签名。
通道绑定
即使客户端正在使用 TLS,也可能希望防止中间人攻击,这种攻击拥有有效的服务器证书,但不是对客户端进行身份验证的方。通道绑定允许客户端将断言绑定到 TLS 服务器证书或会话。然后,验证断言的服务器可以验证它是否与发送到客户端的证书匹配。(通道绑定只是断言中的一个额外声明,受与其他声明相同的信任链保护。)
密钥交换
并非所有应用程序协议都使用 TLS。某些协议(例如 NFS 和 CIFS)依赖于身份验证协议协商的密钥来签名并可能加密消息。其他协议可能支持 TLS 但不需要它。因此,让客户端和服务器就会话密钥达成一致可能很有用。我们通过让客户端和服务器执行椭圆曲线 Diffie-Hellman (ECDH) 密钥交换来实现此目的。生成的共享密钥可用于使用 SHA-1 哈希算法和 128 位或 256 位 AES 对消息进行签名和加密。
可以使用其他哈希和加密算法,而无需更改基本协议;这些是我们目前定义的算法,它们基于当前 Kerberos 实现所使用的算法。设计良好的实现应该能够进行现场升级以支持新算法。
我们还提供了一个伪随机函数,以便进行自身加密或完整性保护的应用程序可以导出密钥。
双向身份验证
同样,对于不使用通道绑定 TLS 的应用程序,客户端能够对服务器进行身份验证(而不仅仅是相反)会很好。我们通过允许服务器发送回证书来实现此目的,就像在 TLS 中一样。在这种情况下,我们实际上使用的是标准的 X.509/PKIX 证书,而不是 Persona 证书:我们认为,为了能够重用现有的密钥基础设施而牺牲架构对称性是正确的折衷方案。
(我们也可以指定 Persona 证书,但这将需要 IdP 颁发主机证书。并且鉴于 IdP 最终使用 X.509 证书进行身份验证,因此这种方法的价值值得怀疑。其主要优点是可以绕过主机身份验证的 CA 基础设施,因为只需要为 IdP 颁发 X.509 证书。)
快速重新身份验证
邮件客户端等应用程序往往会建立和拆除大量连接,通常是同时建立和拆除。在 JavaScript 中明确使用 Persona 登录和/或执行公钥操作将使 Persona 无法用于这些协议。为了解决这个问题,我们允许服务器返回一个 cookie(称为“票据”,向 Kerberos 致敬),该 cookie 可用于后续重新身份验证。与 Web cookie 不同,此 cookie 绑定到一个加密密钥,因此后续身份验证与原始私钥签名身份验证具有相同的安全级别。我们不是发送用用户的私钥签名的断言,而是使用从初始密钥交换导出的密钥使用 HMAC 对断言进行签名。
综合起来
用于向 mail.example.com 上的 IMAP 服务器进行身份验证的断言可能如下所示
{
"opts": [
"ma"
],
"exp": 1360158396188,
"ecdh": {
"crv": "P-256",
"x": "JR5UPDgMLFPZwOGaKKSF24658tB1DccM1_oHPbCHeZg",
"y": "S45Esx_6DfE5-xdB3X7sIIJ16MwO0Y_RiDc-i5ZTLQ8"
},
"nonce": "bbqT10Gyx3s",
"aud": "urn:x-gss:imap/mail.example.com"
}
“opts”声明中的“ma”表示需要双向身份验证。“ecdh”声明包含所选的 ECDH 曲线和客户端公钥,用于会话密钥协商。“nonce”声明用于双向身份验证,将请求和响应断言绑定在一起。其余声明“exp”和“aud”与 Persona Web 断言相同,只是受众包含服务主体名称。(我们省略了断言上的签名和用户的证书,因为这些与 Web 使用情况没有区别。)
另一个区别是服务器将发送回自己的断言,该断言在交换的密钥或长期私钥中进行签名。它看起来类似于以下内容
{
"exp": 1362960258000,
"nonce": "bbqT10Gyx3s",
"ecdh": {
"x": "bvNF6V1rpMeQyGOKCj0kBaOaSh3tlhUcbffaji4uCEI",
"y": "Iuqs650FXzXFUD9kHknETfbqiB8XBbCHlJXoysx3rvw"
},
"tkt": {
"tid": "Jgg7vKX2sEKlCWBfmLTg_n4qz3NVZxOU-a2B4qYMkXI",
"exp": 1362992660000
}
}
响应断言包含建议的过期时间、回显的随机数、服务器的 ECDH 公钥和用于快速重新身份验证的可选票据。
实现
协议规范都很好,但拥有一个能够与现有应用程序一起使用的实现也很重要。我们的实现可在https://github.com/PADL/gss_browserid获取。
客户端在 OS X 上运行,服务器应该在任何具有 Kerberos 库、libcurl 和OpenSSL 的现代 POSIX 兼容系统上运行。将客户端 UI 移植到其他操作系统应该相当简单;最困难的部分是找到一个可以显示 Web 浏览器控件的库,并实现一个返回断言的函数。在 OS X 上,我们使用内置的 WebKit 框架来实现此目的。(还有一个使用 MSHTML 的 Windows 端口的雏形,但尚未完全完成。我们预计它将在 2013 年底前完成。)
我们的实现分为两个组件,libbrowserid 和 mech_browserid,我们在下面讨论这两个组件。
libbrowserid
libbrowserid 是一个通用的 C 库,用于获取和验证 Persona 断言。如果愿意,您可以不构建 SASL/GSS-API 机制而构建它;如果您想要一个本地代码本地验证器,这可能很有用。(与所有本地验证器一样,请注意 Persona 协议可能会发生变化。我们将跟踪任何更改。)
如果您想了解如何在独立于 SASL/GSS-API 的情况下使用此库,请查看sample/bidget.c和sample/bidverify.c:这两个简短的程序(约 50 LOC)分别演示了如何使用 libbrowserid 获取和验证 Persona 断言。
mech_browserid
mech_browserid 模块是一个插件,构建在 libbrowserid 之上,允许使用 SASL 和 GSS-API 的应用程序无缝使用 Persona。您需要安装最新版本的MIT Kerberos或Heimdal,以及Cyrus SASL(如果您的应用程序使用 SASL)。您还需要一个启用了 ECDH 的最新版本的 OpenSSL 以及 libcurl;OS X 10.8 附带的版本可以正常工作。(针对 OS X 附带的 Heimdal 版本进行构建很困难,不建议这样做。)
要构建,请在顶级目录中运行“autogen.sh”脚本,然后就是通常的“configure”和“make”操作。您可能需要使用 –with-krb5 选项进行配置,以指定您安装 Kerberos 的位置。build/ 子目录有一些用于调用 configure 的示例脚本,您可以根据需要进行调整。为了使 SASL 示例正常工作,您需要使用 -DGSSBID_DEBUG 进行构建,原因如 #ifdef GSSBID_DEBUG on GitHub 中所述。
例如,假设 Kerberos 已安装在 /usr/local 中,您可以键入以下命令:
% ./autogen.sh
% OBJC=clang CC=clang CXX=clang++ OBJCFLAGS="-g -Wall -DGSSBID_DEBUG -Wno-deprecated-declarations" CXXFLAGS="-g -Wall -DGSSBID_DEBUG -Wno-deprecated-declarations" CFLAGS="-g -Wall -DGSSBID_DEBUG -Wno-deprecated-declarations" ./configure --with-krb5=/usr/local
% make
% sudo make install
安装完成后(使用“make install”),您需要在 /usr/local/etc/gss/mech 中添加一行,内容如下:
browserid-aes128 1.3.6.1.4.1.5322.24.1.17 /usr/local/lib/gss/mech_browserid.so
将上面配置文件和库路径中的 /usr/local 分别替换为您安装 Kerberos 和 mech_browserid 的前缀。
测试
您可以使用 Cyrus SASL 发行版中附带的示例来测试 gss_browserid。您需要一个支持 GS2 的最新版本的 Cyrus SASL(您可以通过查看 libgs2.so 是否安装到 sasl2 目录中来判断)。如果您未配置双向身份验证(即您尚未生成服务器证书),那么您还需要对 Cyrus 进行一个小补丁,该补丁可以在 contrib/cyrus-sasl.patch 中找到。应用该补丁并在运行测试之前在 Cyrus SASL 的 plugins 目录中执行“make install”。
首先,确保您的 SASL_PATH 环境变量已设置为 GS2 SASL 插件的安装位置。例如,如果 GS2 SASL 插件安装在 /usr/local/lib/sasl2 中:
% export SASL_PATH=/usr/local/lib/sasl2
启动下面的服务器程序,将 host.example.com 替换为您规范的主机名(但不要使用“-s host”,因为它指定了服务名称)
% server -c -p 5556 -s host -h host.example.com
然后是客户端:
% client -c -p 5556 -s host -m BROWSERID-AES128 host.example.com
如果一切正常,您应该会看到 Persona 登录页面弹出(请记住,此功能目前仅在 OS X 上可用)。输入您的电子邮件地址和密码后,您应该能够进行身份验证(您将在服务器端看到“身份验证成功”)。
如果您再次尝试,它应该无需提示即可工作,因为您将拥有缓存的票据。您可以使用 bidtool 命令列出您的票据:
% bidtool tlist
Ticket cache: /Users/lukeh/Library/Caches/com.padl.gss.BrowserID/browserid.tickets.json
Identity Audience Issuer Expires
--------------------------------------------------------------------------------
lukeh@padl.com host/host.example.com login.persona Tue Apr 23 22:40:36 2013
要删除票据缓存,请使用“bidtool tdestroy”。(Kerberos 用户应该熟悉这些命令。其他有用的命令包括“bidtool rlist”(显示重放缓存)和“bidtool certlist”(显示 IdP 公钥缓存)。还有类似的命令可以清除已过期的条目以及销毁每种类型的缓存。)
如果它不起作用,那么:确实,错误报告目前不是最佳的,调试可能很困难。请确保您
- 使用 -DGSSBID_DEBUG 构建了 libbrowserid;
- SASL_PATH 指向包含 libgs2.so 的目录,并且
- /usr/local/etc/gss/mech(根据需要替换路径)指向 mech_browserid.so 的安装位置。
如果您看到了 Persona 对话框但身份验证失败,请确保您指定的服务器主机名与服务器正在使用的名称匹配。如果您熟悉调试器,则在 gssBidInitSecContext 上设置断点可能会有用。如果其他方法都失败,请 联系我 或发帖到 dev-identity 邮件列表。
为了使本文篇幅简短,我们没有涉及配置双向身份验证(或更准确地说,服务器身份验证)。README.md(位于源代码发行版的顶级目录中)简要介绍了如何配置此功能。gss_browserid 还可以执行其他有趣的事情,例如将证书属性显示给应用程序,即使这些属性嵌入到用户证书内的 SAML 断言隧道中。我们将在以后的文章中讨论这些内容。
应用程序
那么,当您可以使用密码、DIGEST-MD5 或 Kerberos 对(例如)IMAP 服务器进行身份验证时,为什么要使用它呢?以下是一些可能性:您的 Web 邮件提供商希望标准化 Persona 身份验证并弃用基于密码的身份验证(这可能会发生)。您在一家需要使用复杂的多因素身份验证(例如,硬件令牌和客户端证书)的企业工作:构建 Persona IdP 比构建新的身份验证协议要容易得多,因此这允许您将此身份验证策略部署到所有支持 GSS-API 或 SASL 的客户端。(这对于在防火墙外部访问电子邮件可能特别有用。)
在此示例中,我们演示了如何使用 Persona 使用 OS X Mail 客户端进行身份验证。需要提醒您,这并非易事:它涉及安装一个插件,该插件会欺骗 Mail 在您请求 Kerberos 身份验证时使用 Persona。(请注意,这将阻止您从 Mail 使用 Kerberos。并且 Apple 完全不支持此功能。但这毕竟是 Mozilla Hacks 博客,对吧?)
首先,您需要设置您的 IMAP 服务器以支持 Persona,但只要它支持 Cyrus SASL,并且您已在同一台机器上使上述 SASL 示例正常工作,它应该“正常工作”。再次确保 SASL_PATH 设置正确,并且 IMAP 服务器具有对其授权和重放缓存文件的读/写访问权限(在 OS X 上,这些文件将创建在 ~/Library/Caches/com.padl.gss.BrowserID 中;在其他平台上,它们将位于 /tmp 或 $XDG_RUNTIME_DIR 中)。
您可以使用 cyradm 工具测试您的 IMAP SASL 配置(假设您使用的是 Cyrus imapd)。例如:
% cyradm --user lukeh@lukktone.com --port 143 --auth BROWSERID-AES128 rand.mit.de.padl.com
如果在使此功能正常工作时遇到任何问题(您没有看到带有 IMAP 服务器名称的 cyradm 提示符),那么您需要在继续之前对其进行故障排除。否则,请继续安装“伪装为 Kerberos”插件,该插件可以在 gss_browserid 的 contrib/BrowserIDHelper 目录中找到。在该目录中,您可以简单地键入“make && make install”来构建和安装。(要删除它,请删除 ~/Library/Mail/Bundles/BrowserIDHelper.mailbundle。)
您还需要修改应用程序沙箱,以便可以加载 gss_browserid 机制及其配置文件。以 root 身份应用 application.sb.patch 中的补丁,并根据需要调整路径。然后,删除 ~/Library/Containers/com.apple.mail/Container.plist,并启动 Mail。
在您希望使用 Persona 进行身份验证的邮件服务器的“首选项/帐户/高级”中,将“身份验证”设置为“Kerberos 版本 5 (GSSAPI)”。此解决方法是必要的,因为 Mail 不是 SASL 机制无关的;它仅支持一组固定的机制,例如 GSSAPI 和 DIGEST-MD5。
一切顺利的话,系统会提示您登录
就是这样。
结论
今天可以使用 Persona 用于非 Web 应用程序,但在它准备好投入使用之前还有很长的路要走。我们希望完成协议的定义并将其作为 RFC 发布,这反过来又需要底层的 BrowserID(和 JOSE)规范保持稳定。需要使用更多应用程序进行实施测试,并完成对 Linux 和 Windows 的完整移植。假设一组特定 SASL 或 GSS-API 机制的应用程序需要更新为机制无关的。企业用例需要能够从 Active Directory 和其他常见身份验证提供程序桥接的 IdP。
我们期待着在未来几个月见证 Persona 的发展及其如何在非 Web 领域得到应用。
最后,如果您计划构建自己的 draft-howard-gss-browserid 实现,请 直接联系我 或在 ietf-kitten 邮件列表中联系我。
致谢
我的草稿合著者 Nico Williams 就协议设计提供了许多建议。gss_browserid 实现基于 Moonshot GSS EAP 机制,由 JANET(UK) 赞助。还要感谢 Painless Security 的 Sam Hartman 和 Mozilla 的身份团队。
关于 Luke Howard
Luke Howard 于 1999 年创立了 PADL Software。他是 RFC 2307 的作者,并为许多开源项目做出了贡献,包括 OpenLDAP、MIT Kerberos 和 Heimdal。他构建了第一个商业发布的 Active Directory 替代品 XAD,并曾在 Apple 和 Novell 工作。2013 年,他致力于将 Mozilla Persona 引入非 Web 应用程序。他还是一位作曲家和音乐家,曾参与制作了 50 多张专辑,并且曾经为 Brian Eno 做过午餐。
关于 Robert Nyman [荣誉编辑]
Mozilla Hacks 的技术布道师和编辑。发表关于 HTML5、JavaScript 和开放 Web 的演讲和博客文章。Robert 坚信 HTML5 和开放 Web,自 1999 年以来一直从事 Web 前端开发工作 - 在瑞典和纽约市。他还定期在 http://robertnyman.com 上发表博客文章,并且喜欢旅行和结识新朋友。
3 条评论