基于OAuth2.0协议的移动应用认证的破解与修复

1 引言

OAuth2.0 协议最初是为第三方网站的授权需求而设计的。然而,许多主要的身份提供商(IdPs)(如 Facebook、谷歌 和 新浪)最近已采用基于 OAuth2.0 的协议来支持第三方移动应用(在 OAuth2.0 情境下充当依赖方)的单点登录(SSO)服务。当 OAuth2.0 被用作 SSO 方案时,用户可以通过身份提供商(IdP)登录移动依赖方(RP),e.g.,IMDB,而无需将身份凭证共享给依赖方(RP)。在本文中,我们将重点关注 OAuth2.0 和 OpenID Connect(构建在 OAuth2.0 之上),因为它们是 de facto 的 SSO 标准。

为了支持第三方移动应用的单点登录服务,相关文献已对适配的 OAuth2.0协议的安全性进行了评估。Chen等[12]首次指出,实现移动平台上的OAuth2.0需要使用操作系统提供的组件(例如,Android的 Intent/WebView)。Chen进一步表明,如果移动应用开发者未能充分理解这些组件的特性,则可能被利用从而破坏移动单点登录系统的安全。在此基础上,Ye 等[34]采用模型检测方法对这一修改后的协议进行理论评估,而Wang等[28,29]总结了15个中国身份提供者在不同平台上存在的已知漏洞。

先前的研究主要关注移动系统差异(i.e.,系统提供组件中的漏洞)如何破坏移动单点登录系统。然而,在将基于OAuth2.0的协议适配到移动平台时,由于主要协议变更所带来的安全影响常常被忽视。例如,标准的OAuth2.0隐式流程已被证明在认证方面不安全,因此建议采用修订版本,i.e.,OpenID Connect(OIDC)的一种变体。然而,这些研究未考虑到即使在修订版本中,单点登录结果仍需通过用户设备传递。因此,这些关键的安全结果可能遭受篡改,并进一步使攻击者能够推断出RP服务器的程序逻辑。

为此,本研究的目标是进一步理解:(1)如果OAuth1协议流程的变更未能正确实现,可能导致严重的安全漏洞;(2)通过检查现有漏洞是否已被修复,评估移动单点登录系统的整体安全质量。我们的工作包含两个方面:(1)我们对三个第一梯队Android身份提供者应用(Facebook, Google 和 新浪)及其被依赖方广泛使用的相应软件开发工具包进行标准的静态代码分析,以了解其客户端程序逻辑;(2)我们开发了一款工具,用于动态测试美国和中国的前 600个Android应用,以评估依赖方/身份提供商服务器执行OAuth事务的表现。

基于这些研究,本文作出了以下技术贡献: – 我们识别了OAuth协议调用流程中的关键安全变更。 – 我们检查了3家一线身份提供商以及600款美国/中国排名靠前的Android应用的实现情况。除了多种已知类型的漏洞外,我们还发现了三种由于协议调用流程修改的错误实现所导致的先前未知的漏洞。 – 我们设计并实现了一种万无一失的解决方案,可防止未来的第三方应用开发者重蹈覆辙。为便于过渡,我们的解决方案仅需对存在漏洞的移动应用中由第三方开发的代码进行最小改动。

我们使用 OAuth 来表示 OAuth2.0 和 OpenID Connect,除非另有说明。

2 背景

在OAuth生态系统中,为了支持第三方移动应用的单点登录,涉及四个参与方,分别是第三方移动应用的后端服务器(简称RP服务器)、身份提供商的后端服务器(IdP服务器)、第三方客户端移动应用(RP应用)以及身份提供商的客户端移动应用(IdP应用)。为了便于表述,在本文其余部分中,我们使用括号中的符号来表示这四个参与方,并在未特别说明的情况下,使用OAuth表示OAuth2.0以及 OIDC。

单点登录(SSO)的最终目标是让IdP服务器向RP服务器颁发身份凭证,例如,OAuth2.0的访问令牌和OIDC的ID令牌。凭借此身份凭证,RP服务器可确定用户身份,进而使用户登录。

2.1 移动平台上的 OAuth 2.0 隐式流程

OAuth2.0[18]定义了四种授权流程,其中隐式流程和授权码流程分别被移动平台和网站广泛使用。2由于Chen 等[12],人的研究揭示,标准的隐式流程在移动平台上用于认证是不安全的。在修订标准协议后,人们认为一种安全的实现方式如图1所示,尽管RFC和身份提供商均未提供完整的调用流程图。

示意图0

  1. 用户尝试使用身份提供商(IdP)登录依赖方(RP)。RP应用通过移动操作系统提供的安全通道(例如安卓中的Intent通道)将其应用信息(e.g.,请求的权限)发送给IdP应用。

事实上,授权码流程也可以安全地用于移动应用,但会带来性能下降的代价。

  1. 得益于该安全通道,IdP应用可以验证RP应用信息是否正确。如果正确,IdP应用便将此信息作为授权请求发送至IdP服务器。3. IdP服务器将授权请求中的信息与RP开发者预先注册的信息进行比对。如果匹配,IdP服务器便会认为该授权请求有效,从而向其自身的客户端应用颁发访问令牌(AT)以及可选的用户信息(e.g.,uid)。4. IdP应用通过操作系统维护的安全通道将访问令牌返回给RP应用。5. RP应用将访问令牌和用户信息发送给RP服务器。6. RP服务器应调用IdP提供的安全导向的单点登录API(SSO‐API)来验证访问令牌。7. 如果访问令牌有效,IdP服务器应向RP服务器返回授权信息,包括该访问令牌是颁发给哪个RP的。8. 只有当访问令牌属于该RP时,RP服务器才会接受它。此后,RP服务器可使用该已验证的访问令牌获取用户数据。9. IdP服务器返回与该访问令牌关联的用户数据。10. RP服务器便可识别该用户,并将其敏感数据返回给RP应用。

2.2 OpenID Connect 协议

由于OAuth2.0最初是为支持授权而设计的,为了将其用于认证,需要经历多次高延迟的往返通信,即图1中的步骤6–步骤9。1为了更高效地支持认证,谷歌和 Facebook等身份提供商在OAuth2.0基础上开发了OpenID Connect( OIDC)协议[25]及其变体。除了授权码流程和隐式流程外,OIDC还进一步支持另一种授权流程,即混合流程。然而,本研究中所有实际的OIDC启用应用仅实现了隐式流程。因此,本文其余部分将重点讨论隐式流程。

关于隐式流程,OIDC与OAuth2.0向后兼容。唯一的区别是,除了访问令牌之外,身份提供商还引入了一个新参数即,idtoken,该参数由IdP服务器进行数字签名。如图2所示,包含用户资料的ID令牌随后与原始的访问令牌一起发送到RP服务器。由于签名无法被攻击者篡改或伪造,因此依赖方服务器现在可以直接从ID令牌中提取用户资料来识别用户,而无需再从IdP服务器获取用户资料。

示意图1

2.3 威胁模型

攻击者的目标是破坏移动应用认证,i.e.,以受害者身份登录RP应用。在此,我们信任移动操作系统和假设其不会被攻破。我们假设攻击者可以在她自己的设备上安装RP应用和IdP应用,从而与RP服务器和IdP服务器进行通信。攻击者Eve可以充当普通用户,并通过她自己的设备监控或篡改网络流量。此外,我们还考虑攻击者可能诱骗用户在其设备上安装恶意应用。该应用不具有任何被视为危险的权限。

3 影响移动OAuth安全的三大协议变更

尽管上述OAuth协议看似简单,但移动应用开发者在将该协议从网站移植到移动端时,常常会忽略一些与安全相关的改动。

3.1 不受信任的 IdentityProof

网站通常采用授权码流程来支持单点登录服务。在这种情况下,身份凭证通过依赖方服务器和身份提供商服务器之间的安全HTTPS通道传输。相反,移动开发人员提倡使用隐式流程,该流程通过用户设备传递身份凭证。由于移动设备不可信(攻击者完全控制其自己的设备),身份凭证可能遭到篡改。因此,依赖方服务器只能基于两个原因接受此类身份凭证:

  1. RP服务器通过直接的服务器间调用向IdP服务器验证身份凭证(即,图1中的步骤6‐步骤9);2. 身份凭证由IdP服务器签名(即,ID 令牌 ,如图2所示)。

换句话说,RP服务器应与IdP服务器建立直接信任关系,以正确处理身份凭证。

此外,所谓的身份凭证有多种类型,包括访问令牌、ID令牌、用户资料 (如图1的第9步返回)以及授权码(如果使用了授权码流程)。由于协议规范和研究文献均未涵盖这一概念,依赖方开发者需要基于自身对协议的理解,自行决定使用哪种身份凭证以及如何使用。

3.2 客户端侧逻辑过重

另一个主要区别在于用户代理。在基于网页的单点登录服务中,用户操作是在终端用户的浏览器中进行的。相比之下,在移动单点登录系统中,用户与RP应用和IdP应用进行交互(浏览器被分成了两部分)。由于移动应用功能更强大,RP应用和IdP应用通常需要负责更多的消息交换,而这些消息交换在网站场景下是由后端服务器来管理的。这乍看之下似乎合理,但有些消息只能在服务器端处理,例如用户在图1的第9步检索到的资源。否则,可能会导致用户画像攻击,如第5节所述。

同时,身份提供商应用和服务提供者应用在客户端存储了更多的数据。例如,身份提供商应用保存用户身份信息,而服务提供者应用存储授权信息(例如,服务提供者名称),这些信息会显示给用户以供其查看或授予权限。需要注意的是,这些关键安全数据本应在单点登录事务期间从服务器获取。然而,由于这些信息存在于客户端,应用开发者可能会倾向于直接从手机中读取,从而导致所谓的用户画像攻击和服务提供者应用身份不一致问题,如第5节所述。

4 我们的方法

为了评估上述协议变更所带来的安全影响,我们首先对每个依赖方/身份提供商应用进行动态测试。该测试有助于理解服务器端的程序逻辑。其次,为了更好地了解客户端的安全实践,我们对身份提供商应用(i.e.,Facebook、谷歌和新浪)及其对应的软件开发工具包(由依赖方应用使用)进行了深入的静态代码分析。鉴于身份提供商应用和软件开发工具包数量有限,我们可以进行人工代码审查。

4.1 动态测试

我们设计了一种工具,用于自动模糊化每一条与OAuth相关的消息。如图3所示,我们首先设置一个中间人(MITM)代理,以便观察和篡改进出我们手机的网络流量。然后,我们像普通用户一样手动操作手机,模拟单点登录流程,生成一系列OAuth请求。对于每个请求,我们的工具会将每个参数替换为来自不同依赖方和用户的参数。最后,该工具发送模糊化请求至接收方,并检查响应是否正常。需要注意的是,由于网络流量通常受HTTPS保护,我们采用了支持 SSL的代理,例如mitmproxy[3]。

分析IdP应用与IdP服务器之间的通信是直接的,因为此类交互对于同一 IdP具有相同的格式。遗憾的是,对RP应用与RP服务器之间的消息进行模糊测试,即图3中的步骤5(ii),3比预期更具挑战性。首先,用户移动设备与RP服务器之间存在大量交互,因此很难确定哪个请求被RP服务器用于认证用户。其次,除了受到HTTPS保护外,RP应用与其后端服务器之间的消息交换通常还由 RP开发者进一步加密或签名。尽管可以从Android应用中提取加密密钥,但这做法可能不可扩展。因此,通常更容易篡改从IdP服务器到IdP应用的响应, 即改为步骤3(ii)。毕竟,RP服务器接收到的所有与OAuth相关的信息只能来源于IdP服务器3。

示意图2

4.2 静态代码分析

为了理解客户端逻辑,我们反编译了最新的IdP应用以及RP应用广泛使用的官方SDK(如果已编译)。尽管IdP应用和SDK通常经过严重混淆,但特殊活动和系统API(例如startActivity、getCallingPackage、等)的名称并未改变。因此,我们可以识别出单点登录服务的入口,并构建部分调用流程图。这使我们有机会仅关注数量相对较少的与单点登录相关的安全关键活动。随后,我们手动检查这些活动以识别潜在漏洞。例如,我们发现新浪的单点登录入口(即SSOActivity)默认会验证接收到的信息,除非该信息来自新浪自身。这种做法初看似乎合理。然而,如果新浪应用中存在“下一个Intent”[31],恶意RP应用可能利用此机制绕过安全检查。因此,在代码审查过程中,我们会尝试检查“下一个Intent”的存在。为了确认这些漏洞,我们使用官方SDK构建了一个测试用服务提供方应用,并在该测试应用上发起相应的攻击。通过这种方式,我们发现了第5.2节所述的服务提供方身份不一致问题。

5 漏洞分析

除了各种现有漏洞外,上述方法还有助于发现由于对协议变更的错误理解/实现而导致的三个未知安全缺陷。

5.1 资料漏洞

身份凭证通常被RP服务器错误处理,从而导致资料漏洞,使得攻击者仅利用受害者的公开用户资料即可登录易受攻击的RP。请注意,所有这些

先前的研究发现[12,29,34]需要与受害者进行不同类型的交互。相比之下,这一新发现的漏洞可由攻击者远程单独悪用手法,无需欺骗或与受害者交互,例如通过钓鱼攻击。

错误实现的类型。 我们提出两种常见但广泛存在的错误类型(但现实世界中的误用不限于这两种类型)。

向RP服务器返回错误的身份凭证。 一些RP应用可以直接从其运行的移动设备上检索用户信息,而无需依赖从身份提供商(IdP)获取的OAuth访问令牌。在没有访问令牌的情况下,RP应用仅将用户资料(例如,用户ID、电子邮件)发送给RP服务器作为身份凭证。因此,RP服务器无法正确识别用户。

一个有趣的误用情况发生在使用谷歌作为身份提供者时,涉及安卓账户管理系统(AMS)[2,15]。安卓AMS提供了一个集中式数据库(即,/data/system/users/0/accounts.db),用于存储用户账户。尽管AMS的主要目标是通过后台同步支持对用户数据的无缝访问,但谷歌已将其集成以支持单点登录服务。具体而言,当用户登录其谷歌账户时,谷歌登录服务(即,IdP应用)会将用户的谷歌账户信息存储在accounts表中,如下所示。

INSERT INTO " accounts " VALUES (1 , ’ alice@gmail . com ’,’com . google ’,’ password ’, NULL );

通过安卓的GETACCOUNTS权限,应用可通过调用getAccounts()方法轻松获取用户的谷歌账户(即电子邮件地址)。如图4(a)所示,一些RP开发者(例如,某杀毒应用Psafe,拥有 50+百万次安装量)直接将从数据库中获取的该电子邮件地址返回给RP服务器作为身份凭证,而不考虑访问令牌(或ID令牌)。因此,攻击者可在其移动设备的数据库中插入一个伪造条目,即,受害者的电子邮件地址。

另一个典型的示例如图4(b)所示,其中RP应用使用访问令牌调用IdP API 立即获取用户数据。然而,该RP应用仅将其服务器发送的用户资料作为身份凭证。尽管此类凭证除了传输层安全协议外还受到加密/签名技术的保护,但攻击者仍可在图4(b)的第4步提供错误的用户信息。

RP 服务器未验证身份凭证。 如图5(a)所示,当 IdP 服务器通过 OAuth 返回用户身份信息(例如,用户ID/电子邮件地址)以及访问令牌时,许多 RP 服务器(例如,拥有 80+百万月活跃用户的搜狐等等)会简单且错误地将其自身的客户端应用所收到的用户ID作为依据,返回敏感用户信息,而未验证所收到的用户ID是否确实与已颁发的访问令牌绑定(即,缺少图1中的步骤6‐步骤9)。

图5(b)显示了另一种情况,其中Facebook和谷歌采用类似OIDC的协议并对用户身份信息进行数字签名。然而,大多数RP服务器忽略了该签名,并坚持使用传统OAuth协议。更糟糕的是,一些RP服务器(例如,拥有 10+百万次安装量的免费通话/短信应用丁通)甚至未验证签名,而是直接从签名的负载中提取用户ID,并在没有任何认证/验证的情况下接受该用户ID。

利用资料漏洞。 利用图3所示的相同系统设置,攻击者可通过悪用手法受害者的资料,在执行以下步骤后以受害者身份登录易受攻击的应用4:

  1. 攻击者为其自己的移动设备设置一个启用SSL的中间人代理,以监控和篡改进出该设备的网络流量。2. 攻击者在其自己的移动设备上安装存在漏洞的RP应用。3. 攻击者使用其自己的IdP登录名和密码登录到存在漏洞的RP应用中。4. 当IdP服务器将其用户资料返回给其客户端应用时,即图3中的步骤3(ii),3攻击者通过中间人代理将自己的用户ID(对于谷歌+和新浪用户为公开用户ID,或可猜测的电子邮件地址)替换为受害者的用户ID。尽管Facebook自2014年5月起已开始为每个RP颁发每应用私有用户ID,但出于向后兼容性的原因,至今Facebook仍使用公开用户ID来识别早期采用者

对于谷歌安卓AMS的情况,攻击者只需在自己的设备中插入一个伪造条目,然后按照正常的步骤完成单点登录流程即可。

一个存在漏洞的Facebook依赖方应用的用户,只要他在2014年5月之前曾通过Facebook登录过该RP应用,仍然容易受到我们的攻击。

  1. 由于RP服务器直接使用其客户端应用返回的用户身份信息来识别用户,且未进行进一步验证,因此攻击者可以成功以受害者身份登录到RP。

Additional Challenges for the Exploit. 上述悪用手法在身份提供商客户端应用 (例如 Facebook 的应用)实施证书固定的情况下会涉及额外的挑战。在这种情况下,由 IdP 服务器发送(然后被攻击者的中间人代理篡改)给其客户端应用的消息将不会被后者接受。作为变通方法,攻击者可以简单地卸载 IdP 应用,从而使 RP 应用广泛使用的身份提供商SDK 自动降级,通过内置的 WebView 浏览器执行 OAuth 认证。由于 WebView 是一种通用的内置浏览器,因此不支持针对特定身份提供商的证书固定。

但是一些身份提供商不支持WebView。在这种情况下,攻击者无法直接使用Xposed SSLUnpinning等现成工具[6]模块,因为身份提供商通常使用自定义方法(而非原生安卓框架)来实现证书固定。对于此类身份提供商,攻击者必须反向分析IdP应用并手动移除证书固定。为了证明该方法的可行性,我们通过反向分析apk文件成功在Facebook应用上实现了概念验证攻击。然而,依赖方应用(更准确地说,是身份提供商SDK)还会将Facebook的证书与之前硬编码的证书(即Facebook的真实证书)进行比对。因此,我们还需要绕过该证书比对功能。

厂商回应。 本研究涉及的三家身份提供商均承认该安全问题,并承诺协助通知受影响的第三方应用开发者。特别是,新浪已向其平台上的所有RP开发者发送了具体通知,告知此问题。该公司还根据其漏洞奖励计划授予我们最高额度的奖励积分。同时,新浪已相应更新了其编程指南中的单点登录部分。谷歌已通过其谷歌安全名人堂确认了我们的发现,并表示将修改面向第三方应用开发者的相关文档。Facebook已告知我们,他们正在寻求让其RP开发者了解此问题的方法。

5.2 用户视角下不一致的RPApp身份

在图1的步骤2对用户进行认证后,IdP应用应从其后端服务器检索授权信息,包括RP名称和请求的权限。从用户的角度来看,IdP应用将弹出一个对话框,显示哪个RP向哪个用户请求了哪些权限。此处,RP的名称代表由IdP验证的 RP身份。

由于该授权信息也被RP应用存储在移动设备上,我们发现谷歌会立即从设备中获取此类信息。具体而言,当RP应用采用Intent5 scheme(这是谷歌官方SDK使用的默认方法)来支持单点登录服务时,谷歌会根据android:label在 AndroidManifest文件中的值显示RP的名称。一方面,谷歌实际上能够正确识别RP的身份;另一方面,AndroidManifest文件可由RP应用任意定义。因此,所显示的授权页面与谷歌的理解不一致。

利用这种不一致性,恶意RP应用可以欺骗用户,使其相信正在交互的RP (由谷歌验证)是一个类似IMDB的良性且具有特权的应用。由于用户对谷歌高度信任,当谷歌将该RP应用验证为IMDB而非某个随机应用时,用户便更愿意授予相应权限。因此,恶意RP更容易获取访问令牌。该访问令牌使攻击者能够获取受害者存储在谷歌上的数据。结合其他攻击方式e.g.,如令牌劫持,攻击者还可以登录受害者在其他支持谷歌的良性应用上的账户。

厂商回应。 谷歌确认了这一安全漏洞。但据谷歌安全团队称,此安全问题已被另一项并行研究独立发现(但该问题尚未修复)。不幸的是,只有首个报告才属于谷歌漏洞奖励计划的范围。

5.3 将IdP应用视为特殊的依赖方

一些身份提供商(IdP),包括谷歌和新浪,将其客户端应用视为特殊的依赖方 (RP)。如果用户能够成功通过IdP的身份验证,IdP服务器将向其客户端应用颁发一个访问令牌。请注意,此访问令牌具有更高权限,它使IdP应用能够代表用户执行敏感交易,例如为任何其他易受攻击的RP颁发访问令牌等。由于攻击者(以普通用户身份)也能获取该访问令牌,因此可以轻易发起应用仿冒攻击 [20]。例如,攻击者可利用这一高权限的访问令牌调用原本不允许攻击者或用户使用的敏感API(例如,批量查询用户信息),并享有更高的API配额。

更糟糕的是,新浪应用中的这个特权访问令牌并未受到HTTPS保护。因此,攻击者可以通过窃听轻松获取该令牌。利用这一特殊访问令牌,攻击者可以冒充受害者进行任何交易,例如以受害者的身份登录新浪平台上的任意RP应用。

厂商回应。 我们已向新浪报告了此问题。新浪直接承认了该问题,并已为其 Android应用应用了相应的修复措施。

6 评估

我们研究了由三家顶级身份提供商提供的Android IdP应用和OAuth SDK,即 Facebook、谷歌和新浪。这些身份提供商的注册用户数量从超过8亿到超过25亿不等,如表1所示。随后,我们对在美国和中国排名前600的安卓应用进行了全面测试。

由于更多中国的易受攻击的RP支持OAuth,我们仅从一个主要的中国应用商店中选择总体类别排名前100的易受攻击的RP,以及在不同类别中排名前100的应用用于新浪 [4]。相比之下,我们从Google Play中为Facebook和谷歌分别选择了总体类别排名前300的易受攻击的RP,以及不同类别中排名前100的易受攻击的RP。在不同类别中排名前100的应用选择方式如下:社交类免费应用前30名、旅行与本地类免费应用前30名、健身类免费应用前30名、通信类免费应用前10名。在这600个应用中,我们发现有182个应用使用了上述三个身份提供商中的一个或多个提供的 OAuth认证服务。

表1. 协议使用情况的统计数据

身份提供商 (# 第三方依赖方) 身份提供商用户数 (单位:百万) OAuth2.0 不安全 使用 OAuth2.0 正确 使用 OpenID Connect 忽略 ID 令牌 OpenID Connect 未验证 ID 令牌 OpenID Connect 正确 使用
Facebook (59) >1,500 9 10 35 (20∗) 2 3
谷歌 (40) >2,500 24 14 0+ 0 2
新浪 (83) >8,00 78 5 N.A N.A N.A

– ∗:35个依赖方中有20个存在错误实现。
– +:谷歌对OIDC协议进行了定制,通常仅向依赖方发放ID 令牌。因此,此ID令牌不可忽略,否则将无法提供有效的身份凭证。

除了不同类型的漏洞外,我们的研究还首次提供了关于OAuth2.0和 OIDC采用率以及误用率的一手信息。如表1所示,所有三家身份提供商均支持 OAuth2.0协议。Facebook和谷歌还额外开发并推广用于单点登录服务的类 OIDC协议。由于Facebook SDK默认支持OIDC,因此68%的Facebook应用 (相比之下,谷歌仅有2个RP应用)采用了OIDC协议。然而,这些支持 OIDC的依赖方存在两种类型的误用:

忽略 ID令牌 :某些易受攻击的RP会忽略 ID令牌,在这种情况下,这些易受攻击的RP会退回到OAuth2.0协议,并依赖访问令牌来认证用户。因此,这些易受攻击的RP(35个中有20个)具有与OAuth2.0相同的安 全问题,如表2所示。
未验证 ID令牌 :某些易受攻击的RP确实依赖 ID令牌 来验证用户。但其中29%并未检查ID令牌 是否经过正确签名。

表2. OAuth 漏洞的统计数据

身份提供商(第三方依赖方数量) 资料攻击 令牌劫持 不适当代理 访问令牌 泄露 应用密钥 泄露 易受攻击的数量 RPsa
Facebook (59) 9 (15%) 27 1 2 0 31 (53%)
谷歌 (40) 8 (20%) 20 1 1 0 24 (60%)
新浪 (83) 58(70%) 15 7 13 4 78(94%)
总结(182) 75(41%) 62 9 16 4 133(73%)

– a:一个依赖方可能同时存在多个漏洞, e.g.,例如资料攻击和令牌劫持。

这些观察结果表明,OAuth2.0 仍然是最受欢迎的单点登录协议。不幸的是,OAuth2.0 的实现(包括忽略ID令牌 情况下的 OIDC)也更容易受到攻击:75% 启用 OAuth2.0 的易受攻击的RP 至少存在一个漏洞,而 29% 支持 OIDC 的易受攻击的RP 存在漏洞。不同的 OAuth 安全漏洞汇总于表2中。接下来,我们首先讨论资料攻击的影响,然后展示现有漏洞的普遍性。

6.1 资料攻击的影响

如表2所示,测试中的依赖方中有41%被发现易受新发现的资料攻击。表3列出了我们迄今已识别的部分易受攻击的应用。请注意,此不完整列表中这些受欢迎但存在漏洞的应用的总下载次数已超过24億次。根据Janrain最近调查中51 %的SSOユーザー採用率[7],,我们保守估计,截至目前,超过10億个不同类型 的移动应用账户容易受到资料攻击。

在利用我们的悪用手法登录受害者存在漏洞的RP应用账户后,攻击者通常能够完全访问由存在漏洞的RP服务器托管的受害者的敏感和私密信息。仅表3中列出的易受攻击的应用就暴露了大量极其敏感的个人信息:包括详细的旅行行程、个人/私密通信档案、家庭/私密照片、个人财务记录,以及受害者的浏览或购物历史。对于某些依赖方而言,与受害者账户关联的在线货币/服务积分也会任由攻击者处置。

尽管我们当前的攻击是在Android平台上进行演示的,但该悪用手法本身是プラットフォームに依存しない:只要用户之前曾将OAuth SSOサービス与易受攻击的移动应用一起使用过,无论是iOS还是安卓的用户都会受到影响。作为概念验证,我们已在两个存在漏洞的iOS应用上实施了相同的攻击。

6.2 重新发现已知漏洞

表2显示,我们的测试还重新发现了多种现有的安全问题。

表3. 易受攻击的应用程序及所暴露的敏感信息的部分列表

应用类型 支持的IdP 应用数量 下载(在 百万) 类型 私密/敏感 信息 暴露 交易可由 攻击者
旅行计划应用 Sina >270 旅行行程 -
酒店预订应用 Facebook, Google >5 住宿历史 支付房费 预订
私密聊天应用 Sina >10 私密 消息/相册 发送伪造的 消息
交友应用 谷歌, 新浪 >5 交友历史, 偏好 购买礼物
金融应用1 Sina >25 个人 收入/支出 -
金融应用2 Sina >50 股票列表 兴趣 -
通话应用 Facebook >10 联系人列表和 通话记录 免费通话
直播视频应用 Sina >15 主持人 the 受害者喜欢 购买礼物
下载应用 Sina >60 下载历史 享受VIP速度
购物应用 Facebook, Google >100 购物历史 -
浏览器 Sina >40 浏览历史 -
视频应用 Sina >700 观看视频 历史 购买视频
音乐应用 谷歌, 新浪 >800 播放列表 购买 音轨
新闻应用 Sina >350 新闻阅读 历史 -
  1. 令牌劫持 [1] :在图1的步骤6–步骤7中,RP服务器必须检查收到的访问令牌是否已授予同一RP。不幸的是,34%的RP未能做到这一点,这使得攻击者可以利用颁发给恶意RP的访问令牌登录到受害者的良性RP账户。

  2. 不适当的用户代理 [12] :除了无法识别RP应用外,作为嵌入在应用中的自定义webkit浏览器,WebView也不适合作为OAuth用户代理。由于 WebView受RP应用控制,恶意RP应用能够窃取用户在WebView中提交的任何信息(e.g.,用户的IdP密码),并修改WebView中显示的授权信息。不幸的是,大多数RP应用都支持WebView,更糟糕的是,5%的RP应用仅支持这种存在问题的方案。

  3. 访问令牌泄露 [27] :访问令牌应安全传输。得益于TLS更高的采用率,仅有 9%的移动RP泄露其访问令牌,而32%的第三方网站犯了此类错误 [27]。

  4. 应用密钥泄露 [29] :机密应用密钥应仅在RP服务器和IdP服务器之间共享。有15个移动RP应用部署了授权码流程而非隐式流程。不幸的是,其中27%的应用无意中通过用户设备传递此密钥。这使得攻击者能够以RP的身份执行操作,例如,更改RP的安全设置。

7 可能的根本原因

我们对各种错误实现的普遍存在感到惊讶,因此还通过检查身份提供商(IdPs)提供的软件开发工具包(SDKs)和OAuth API来尝试分析其根本原因。

7.1 开发者文档不清晰

我们发现,许多与认证相关的安全问题都是由于缺乏明确的指导方针所致。由于OAuth2.0(RFC 6749[18])并非为移动应用认证而设计,各个身份提供商(IdP)开发了不同的基于OAuth2.0的API和SDK的自研扩展,以支持移动应用的单点登录(SSO)。然而,这些自研适配的隐式安全假设和操作要求通常没有被清晰地记录,也未被依赖方开发者充分理解。例如,在图1的步骤4中,新浪将用户资料返回给RP应用的唯一目的是允许RP应用显示用户信息(例如用户名、头像等)。尽管有此特定意图,新浪却在其编程指南 [5]中做出了以下令人困惑的声明6:

为了方便应用开发者,返回的用户信息可以避免调用用户资料 API,即 users/show。

如第3节所述,标准OAuth2.0协议必须通过服务器间调用来验证不可信的身份证明。然而,上述说法可能会误导RP 服务器在步骤8和步骤9时不向IdP服务器发起用户资料API调用。相反,RP服务器可能会直接使用其客户端应用返回的用户信息作为身份凭证,从而容易受到资料攻击。

再举一个例子,谷歌假设依赖方开发者会采用OIDC协议,因此仅展示了依赖方应用如何使用ID令牌向其后端服务器进行认证。然而,大多数应用实际上使用的是OAuth2.0协议。对于这些应用,谷歌并未定义依赖方应用与依赖方服务器之间的交互流程。因此,缺乏足够安全专业知识的依赖方开发者不得不自行实现容易出错的认证服务。

在向三家身份提供商报告安全问题后,它们均认识到有必要通过明确指出隐含的安全要求来改进其文档。例如,新浪现在将其声明更新如下:[5]:

第三方应用不应使用 uid来识别已登录的用户。请注意,访问令牌是唯一有效的身份凭证。

6由于新浪开发者并非以英语为母语,因此相关陈述由作者翻译。

7.2 新浪的API设计缺陷

由于更多新浪应用易受资料攻击,我们进一步检查了其软件开发工具包和API 设计。我们发现,新浪糟糕的API设计可能会加剧这一问题。作为一个开放社交网络,新浪在设计上允许任何拥有有效访问令牌的依赖方——无论该访问令牌是颁发给谁的——通过任意用户的users/show API获取其基本资料: https://api.weibo.com/2/users/show.json?access_token=&uid=x 。即使依赖方服务器不信任用户ID,并希望使用访问令牌来识别用户,也可能会错误地使用上述API。在这种情况下,新浪服务器将仅根据URL中 uid的值返回受害者的用户资料。依赖方开发者若未意识到所返回信息的确切语义,可能会错误地认为返回的用户资料与访问令牌绑定,从而导致用户被登录。

事实上,新浪也提供了一个正确的API(即, account/get_uid)来获取访问令牌所绑定的用户ID。但新浪从未明确指定应使用哪个API7。由于不恰当的 users/show API8,提供了更丰富的信息,我们相信依赖方开发者更倾向于使用错误的API。相比之下,Facebook和谷歌使用的是people/meAPI,该接口含义更清晰,更重要的是通常由身份提供商SDK处理。例如,Facebook的PHP SDK会硬编码用户ID me,因此攻击者提供的 uid将被SDK忽略。

8 防御机制

社区提出了以下当前最佳实践(CBPs):
1. 身份提供商应提供更清晰且更注重安全性的开发者指南。
2. 依赖方服务器不应信任任何信息,即使该信息由其自身应用签名。信任应直接基于身份提供商服务器建立。
3. 为移动应用实现OAuth2.0时,依赖方开发者应严格遵循[14],使用授权码流程而非隐式流程。
4. 尽可能使用OIDC进行认证。

如果能够正确遵循这些CBP,那么大多数漏洞将不会存在。不幸的是,大多数 RP开发者根本没有遵守这些CBP。为此,防御的关键在于强制执行定义的安全检查,这不能简单地依赖RP开发者,而必须由具备足够安全专业知识的IdP进行强力实施。因此,我们从IdP的角度出发,开发了一种通用且万无一失的解决方案,以帮助RP开发者自动处理容易出错的SSO服务。我们的解决方案应实现三个目标:

  1. 所有已识别的漏洞(包括现有漏洞)都可以被防止。
  2. 为了简化过渡,依赖方开发者所需的代码更改应尽可能少。
  3. 该解决方案应具备向后兼容性,即RP服务器仍能支持使用旧版本RP应用的用户。毕竟,并非每位用户都能轻易升级其RP应用。

基于这些目标,我们首先回顾现有单点登录系统的架构。如图6所示,RP 服务器和RP应用均可分为两个模块:由身份提供商提供的软件开发工具包负责与身份提供商应用/服务器进行交互,而由依赖方开发者实现的上层代码则管理其自身的业务逻辑。目前,身份凭证的处理也(不正确地)由上层代码完成。

为防止单点登录错误,我们将此类功能迁移到下层的软件开发工具包中,因为我们相信身份提供商提供的软件开发工具包能够正确处理这种安全关键的身份证明。具体而言,在图1的步骤4接收到身份凭证后,客户端SDK可将其发送至服务器端SDK。后者则利用该身份凭证执行真实认证任务。接下来我们将讨论更多细节。

8.1 客户端软件开发工具包的防御机制

如图4所示,当RP应用仅返回用户信息时,RP服务器无法正确识别用户。因此,强制版本的客户端SDK应自动将包括访问令牌(或OIDC的ID令牌)在内的必要信息发送至其后端服务器。考虑到过渡的便捷性,下面我们首先讨论现有客户端SDK的设计。

现有客户端SDK的API设计。 我们仅以 9一个OAuth2.0 身份提供商新浪为例。当授权成功后,客户端SDK(由RP应用使用)将利用安卓 API onActivityResult接收来自新浪应用的访问令牌及用户ID。在将此结果转发给上层之前,authorizeCallBack API会首先被调用以检查访问令牌是否为正确格式。

protected void onActivityResult(...){
    mSsoHandler.authorizeCallBack(requestCode, resultCode, result);
}

使用基于Cookie的方案的初步尝试。 在不影响上层行为的情况下,我们设法在 SDK中认证用户。参考网站中的方案,一个自然的尝试如图6所示,是使用cookie。

  1. 客户端之后 -侧边软件开发工具包(i.e.,授权回调) 检查格式的访问令牌,客户端SDK不会将其转发给上层,而是首先将访问令牌传递给服务器端SDK。
  2. 服务器端SDK严格遵循图6中的步骤3–步骤4(对应于图1中的步骤6–步骤9)通过访问令牌识别用户。
  3. 如果验证成功,服务器端SDK则在图6的步骤5向客户端应用设置一个包含随机nonce的cookie。之后,客户端SDK才会将访问令牌和用户资料转发给上层代码。
  4. 从上层的角度来看,一切保持不变。因此,它可以按照其原始逻辑与RP服务器进行交互。唯一的区别是在图6的步骤7中,一个cookie将自动附加到认证请求上。
  5. 无论RP应用发送的其他信息如何,服务器端SDK仅依赖 cookie来识别用户。

不幸的是,这种基于cookie的解决方案并不适用于所有RP应用:与可以依靠中央浏览器来管理cookie的网站不同,安卓应用开发者需要自行管理 cookie,例如使用CookieManager。因此,底层SDK设置的cookie可能不会被上层自动使用,如果上层采用了自定义的CookieStore。

改进的防御。 然而,基于Cookie的方案仍然提供了重要的启示。请注意, cookie用于绑定图6中步骤2和步骤7的请求。为此,客户端SDK及其上层代码必须共享一些信息,例如cookie。此外,共享的信息必须是一个密钥,否则攻击者可以轻易猜测或计算出该信息,并冒充他人。

鉴于这些要求,我们修改了基于cookie的解决方案。参考Facebook按应用发放私密用户ID的做法,我们将随机生成一个一次性用户ID,而不是 cookie,作为绑定这两个请求的密钥。具体而言,如果认证成功,服务器端SDK会在图7的步骤5向其客户端SDK返回一个随机生成的 uid。该 uid的作用与 cookie相同。请注意,此 uid只能被一次性使用,以防止攻击者猜测或计算其值。一旦过期或使用后,旧的 uid将被删除。

8.2 服务器端SDK上的防御机制

在图7的步骤2中,服务器端SDK可以按照图7(即,对应图1中的步骤6–步骤9)中的步骤3和步骤4来识别用户。认证成功后,服务器端SDK会随机生成一个具有特定前缀的一次性 uid,并维护< uid与 uid_real >之间的映射关系。在图7的步骤7中,服务器端上层应将认证请求转发给其SDK。SDK中新增加的功能随后可以根据请求内容处理该请求。

  1. 如果请求仅包含用户ID,即, uid,我们检查该 uid是否以特定前缀开头。如果是,则检查< uid、 uid_real >的映射,然后获取用户信息 uid_real。否则,直接中止请求。
  2. 如果请求仅包含访问令牌,则按照图7中的步骤3和步骤4来识别用户。
  3. 如果请求同时包含访问令牌和用户ID,则首先按照情况(1)处理用户ID。如果失败,则接着按照情况(2)处理访问令牌。

备注。 我们防御机制的正确性基于两个假设。首先,如图1和 2所示,OAuth 协议的正确实现自动免疫所有现有攻击。事实上,[34]已提供了形式化证明。更准确地说,该工作利用模型检测方法分析Facebook的实现级协议,仅当恶意应用拥有根权限时才能发现未授权的存储访问。然而,本文并未考虑如此强的威胁模型。其次,具备足够安全专业知识的身份提供商(即,软件开发工具包)能够准确地实现协议(而依赖方开发者则经常出错)。因此,我们解决方案的关键在于强制身份提供商开发者为依赖方开发者正确实现OAuth协议。

尽管该防御机制的设计看似复杂,但我们仅向当前系统中增加了两个请求(即,图7中的步骤2和步骤5)。请注意,其他步骤(例如,步骤6、步骤8等)已存在于现有系统中。为了便于说明,在图1中讨论协议流程时,我们有意隐藏了这些详细的(SDK级)步骤。还需注意,所提出的补救措施不会影响授权码流程,尽管我们可以采用相同思路来提升其安全性。

8.3 实现与评估提出的防御

为了验证所提出补救措施的可行性,我们在新浪提供的示例应用上实现了该解决方案。与来自其他身份提供商的示例类似,该示例应用基于安卓软件开发工具包构建。请注意,该SDK处于可执行的 Jar 文件形式。为了修改它,我们需要将 Jar 文件反编译为 Java 代码。尽管存在 CFR 或 JAD 等现成的 Java 反编译工具,但提取出的源代码结构混乱且包含各种错误,需要大量手动修复。

然后,我们遵循通用实践,在官方 PHP SDK 的基础上构建一个后端服务器。服务器端 SDK 中唯一的更改是添加一个执行真实认证任务的新功能。同时,我们在服务器端上层仅添加了 5 行代码,这表明 RP开发者所需的编程工作量最少。

表4. 三种不同设置下的平均运行时间

两种类型的应用 用户信息 (in ms) 访问令牌 (in ms) 访问令牌 & 用户信息 (单位:毫秒)
易受攻击的应用 4490 7604 5092
已修复的应用 6414 9667 6009

评估。 为了证明有效性,我们对示例应用发起了表2中列出的不同攻击。结果表明,我们的解决方案能够防止(或警告不安全传输,例如,令牌泄露)所有这些攻击。例如,由于攻击者无法猜出随机生成的一次性 uid,资料漏洞将不再可能。再以令牌劫持为例。由于我们的防御机制严格遵循图1,我们的服务器端SDK将在图7的步骤3(对应于图1的步骤6)验证该访问令牌是否由自身签发。因此,来自另一个RP的访问令牌将不会被接受。

为了展示我们解决方案的效率,我们测量了一次完整单点登录流程的运行时间。具体来说,我们枚举了第8.2节中提到的认证请求的所有三种可能情况。对于每种情况,我们在相同的手机和网络环境下操作示例应用完成20次 OAuth2.0流程。平均时间如表4所示。结果表明,已修复的应用对用户性能的影响很小。

最先进的OAuth防御。 当前最佳实践(CBP)[14]建议使用授权码流程以防止许多现有问题。然而,对于RP开发者而言,正确实现这些CBP仍然具有挑战性(修订后的隐式流程也是如此)。此外,从隐式流程(当前defact标准)迁移到授权码流程需要大量努力。Xing et al.[32]提出了HTTP参数的不变式,以保护OAuth2.0等第三方Web服务集成。然而,它无法发现许多攻击,例如资料攻击。另一种防御机制[11]使用程序验证器来检查方法调用序列是否满足定义的谓词。尽管该方法功能强大,但仍需要大量努力。

9 相关工作

从协议角度进行的安全分析。 互联网工程任务组在RFC6749[18]和RFC 6819[22]中针对OAuth2.0协议的初始设计提出了全面的安全考量和威胁模型。此外,只要正确使用传输层安全协议,授权码流程已在密码学上被证明是安全的[10]。Hu等[20]提出了应用仿冒攻击。这些工作主要从协议设计的角度证明了Web端授权的安全性。然而,我们关注的是该协议在移动平台上的认证实现是否安全。

OAuth的形式化安全证明。 模型检测方法被大量研究广泛用于分析协议规范 [18],包括 [8,9,16,24],,仅举几例。研究人员还尝试通过建模复杂的运行时平台(例如,浏览器 [16,17])来使用相同的方法推理协议实现。所有这些研究均假设协议调用流程的正确实现。然而,我们发现协议常常被错误地实现。

基于Web的单点登录系统的现实研究。 更多研究致力于基于网站的现实系统中的漏洞检测,包括 [13,23,27,30]。另一个研究方向是对 Web 单点登录系统进行大规模测试,包括 SSOScan [26,35], OAuthT- tester[21,33]。然而,迄今为止提到的所有工作仅研究网站上的 OAuth/OIDC 规范/实现。相比之下,我们的重点是移动平台。

移动OAuth单点登录系统分析。 在移动环境下,针对OAuth的安全分析相对较少。Chen等[12]指出,现实世界中的OAuth系统在使用操作系统提供的组件 (例如,Intent、WebView,等)时可能陷入常见陷阱。Ye等[34]利用模型检测方法评估了Facebook在Androidプラットフォーム上实现的类OIDC协议。Wang等[19,29]汇总了这些已知漏洞的统计数据。上述研究主要关注移动系统的经典漏洞(或特性)如何被利用以破坏单点登录系统。相比之下,我们分析的是修改后的协议调用流程本身如何被错误实现。

10 结论

本文报告了一项关于基于移动OAuth2.0的单点登录系统的实地研究。我们对三个第一梯队的身份提供商应用及其官方SDK以及对中国和美国排名前600的安卓应用进行动态测试。除了发现三个先前未知的安全缺陷外,我们还展示了各类现有漏洞的普遍性。这些漏洞的广泛存在促使我们为易受攻击的依赖方设计并实现了一种可靠的防御机制,旨在最小化依赖方开发者的编程工作量。我们的发现表明,各方迫切需要重新审视其OAuth实现,并相应地应用修复措施。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐