关于OAuth客户端冒充和认证介绍

122 阅读13分钟

我最近从一系列的活动中回来,围绕着各种OAuth相关的话题进行了很多有趣的讨论。在3月份的维也纳IETF官方会议上,我介绍了OAuth 2.1的最新工作,我们讨论了当前的一些开放问题并取得了进展。在几周后的OAuth安全研讨会上,我提出了一个关于移动应用客户端认证的会议,还有很多关于各种主题的演讲。我们中的许多人从那里直接去了欧洲身份和云计算会议,在第二周继续这些讨论。

在这一系列的活动中,有一个反复出现的主题是关于OAuth客户端冒充和认证的想法。

什么是OAuth客户端冒名顶替?

简而言之,OAuth客户端冒充是指一个OAuth客户端假装成另一个客户端,通常是为了利用合法客户端可能具有的、不授予其他客户端的任何功能。

在OAuth术语中,"保密客户端 "是指由授权服务器发放凭证的应用程序,在做请求访问令牌等事情时,可以使用这些凭证来向OAuth服务器验证自己。该凭证可以是一个简单的客户秘密,也可以是一个更安全的选项,如用于签署JWT的私钥。使用任何类型的客户端认证的好处是,假设客户端适当地保护其凭证,OAuth服务器就会知道用这些凭证提出的任何请求都是来自合法的客户端,而客户端冒名顶替就不可能了。

另一方面,"公共客户端 "是一个没有凭证的应用程序,因此在联系授权服务器执行任务(如请求访问令牌)时无法证明自己的身份。通常情况下,这是因为不可能以一种保密的方式来部署这样一个带有凭证的应用程序。公共客户端的常见例子是单页应用程序和移动/桌面应用程序。在这两种情况下,如果你试图在应用程序中包含一个客户端秘密,任何人都有可能提取该秘密,这意味着它将不再是秘密。由于这个原因,一直以来,公共客户端的OAuth流程都是用完全公开的信息完成的。

最初,对于SPA和移动应用,都推荐使用Implicit流程。后来,代码交换的证明密钥(又称PKCE)被引入,作为授权代码流的额外安全功能,主要针对移动应用程序。随着浏览器的发展,最终也可以在单页应用中使用PKCE进行授权代码流。目前的OAuth安全最佳实践草案废除了Implicit流程的使用,并建议在SPA和移动应用程序以及Web服务器应用程序中使用PKCE。也就是说,这个建议与客户端冒充没有关系。PKCE解决了许多不同的攻击,甚至解决了用客户端秘密仍有可能的攻击,但它不是客户端认证的一种形式,所以它不能解决公共客户端的客户端冒充攻击。

对于公共客户,无论是Implicit流程还是带有PKCE的授权码流程,都只用客户的公开信息:client_idredirect_uri 。由于没有使用客户端认证,任何人都有可能利用这些信息,通过做一个看起来与真正的应用程序相同的OAuth流程来假装是该客户端。

我应该担心客户端的冒充吗?

也许是,也许不是!客户端冒充是否会被用于任何不良目的,取决于你在系统中如何对待OAuth客户端。许多公司根本就不关心这个问题。有很多情况下,能够冒充客户端实际上对攻击者一点好处都没有。

让我们仔细看看,如果客户端可以被冒充,攻击者可能有兴趣做的一些事情。

授权服务器是所有关于发放令牌的决定的地方,比如令牌应该持续多长时间,令牌上应该添加什么要求。有时,这些决定涉及的政策取决于将收到访问令牌的客户应用的身份。如果一个攻击者冒充了一个有效的客户端,授权服务器就会对来自攻击者客户端的请求使用有效客户端的策略。

绕过同意屏幕

一个例子是决定是否显示同意屏幕以告知用户他们正在登录哪个应用程序。对于第三方应用程序,同意屏幕是流程的一个关键部分,它传达了哪个应用程序正在请求访问用户的账户,以及哪些信息将与该应用程序共享。对于第一方应用程序,即应用程序与被访问的数据是同一品牌,向用户征求这一许可不一定有意义。例如,如果Twitter应用程序要求你允许访问你的Twitter数据,这将是很尴尬的。出于这个原因,许多公司希望绕过第一方应用程序的同意屏幕。有了这个政策,再加上公共客户端,冒充第一方应用程序意味着绕过同意屏幕,立即向冒充的应用程序发放令牌。

如果你在自己的设备上对自己的账户这样做,基本上不会有什么结果,但如果你能在别人的设备上这样做,可能会更有趣。

在登录一个应用程序时,一个典型的顺序是点击 "登录 "按钮,输入你的凭证,被提示同意屏幕,然后被重定向到应用程序。

如果用户已经登录了,授权服务器可以选择跳过凭证提示。如果用户之前已经同意了这个应用,或者对于第一方的应用,授权服务器也可以选择跳过同意屏幕。在这种情况下,重定向将是即时的,这对用户体验是好的,但如果客户端有可能被冒名顶替就不好了。同样,这对于保密的客户端来说并不是一个问题,因为如果客户端可以认证的话,客户端的冒充就不是一个问题。但对于公共客户来说,由于OAuth流程只使用公共信息,客户冒名顶替肯定是可能的。也就是说,最初的OAuth 2.0规范在安全考虑的第10.2节中明确指出了这一点。原始规范中推荐的缓解措施是要求重定向URL注册,并避免跳过同意屏幕。这让最终用户有机会发现任何试图欺骗他们授权恶意应用程序的行为。

获得特许的API访问权

一些服务可能会限制某些API,只能由特定客户使用。如果服务有一些API只能从特定的移动应用中调用,服务可能希望拒绝来自其他应用的请求,这些应用正在访问系统的其他部分。此外,一些服务可能为不同的客户设置不同的API速率限制,这取决于开发者的信任程度,或者客户是第一方还是第三方客户。

为了做到这一点,API需要知道一个访问令牌是发给哪个客户的。通常情况下,授权服务器会将应用程序的客户端ID嵌入到访问令牌的一个索赔中。这样一来,API在验证令牌的时候就可以访问客户端的id。当然,这种信息只有在授权服务器确信确实是那个应用程序在提出令牌请求的情况下才有效。同样,如果客户端能够自我验证,那么这就相当可靠了。但是对于公共客户端来说,确定性就会大打折扣。

当你在构建基于应用程序限制功能的API时,请牢记特权访问。

常见问题

考虑到这些问题,让我们来回答几个关于OAuth客户端冒充的快速问题。

客户端冒充是一个新问题吗?

根本不是!事实上,在2012年最初的OAuth 2.0规范RFC 6749中就提到了客户端冒充的问题!第二年,"威胁模型和安全考虑因素 "文件完成,并成为RFC 6819。该文件有一大段专门讨论客户端冒充的话题。该部分值得一读,以了解关于减轻这种风险的各种方法的更多信息。

客户端冒名顶替是OAuth特有的问题吗?

由于前面提到的原因,客户端冒充与OAuth有关,但这些问题也可能与根本不使用OAuth的系统有关。

这是一个在移动应用游戏中普遍存在的问题。让我们举一个简单的例子,为一个移动游戏应用建立一个排行榜服务。为了说明问题,我们假设该应用没有任何用户账户的概念,并希望在游戏中显示来自全球该应用所有用户的高分排行榜。为了让游戏服务器收集高分数据,它提供了一个API端点,游戏可以向其报告分数。该API希望只接受来自游戏应用的真实实例的POST请求,而不是那些试图作弊并向API发送假分数的人。

如果没有移动操作系统的支持,API调用中没有任何东西可以验证移动应用程序,因为应用程序发出的任何HTTP请求都有可能被应用程序之外的人模仿。

PKCE能解决客户端冒充问题吗?

没有!这是一个常见的混淆点,可能是因为PKCE最初是如何开发和推出的。PKCE最初被描述为一种让移动应用程序安全地进行授权代码流的方法。但请记住,这要追溯到2015年,当时人们仍然建议移动应用程序使用隐式流程或没有证书的授权代码流程。

尽管PKCE最初被描述为一种针对移动应用的技术,但它并不是客户端认证的替代品,也从未试图假装它是。PKCE可以防止一些特定的攻击,主要是授权代码拦截和授权代码注入。有趣的是,即使应用程序确实使用了客户秘密或其他客户认证,授权代码注入也是可能的。这就是PKCE现在被推荐给所有类型的OAuth客户端的原因,不管它们是移动应用、SPA,还是带有证书的服务器端应用。

说到底,PKCE并不是客户端认证的一种形式,所以它并不能解决客户端冒充的问题。PKCE仍然是一个好主意,因为它可以防止其他值得注意的攻击。

是否有任何针对客户端冒充的解决方案?

到今天为止,还没有任何可靠的机制来验证浏览器中的纯SPA客户端。浏览器可以做的任何事情都可以在浏览器之外被模仿。谷歌浏览器甚至有一个开发者工具,可以让你把浏览器的任何请求复制成cURL命令,在命令行上重放。

对于移动应用程序,有更多的希望。苹果有一个被称为 "App Attestation "的API,谷歌也有一个类似的API,叫做 "Google Play Integrity"。这两个API的工作原理相似,但有一些技术上的差异。在高层次上,它们都涉及应用程序向操作系统提出请求,以签署一些数据。然后,应用程序在调用开发者的API时包括该签名字符串。API可以根据苹果和谷歌的公钥来验证签名,以确定其信任度,即该API请求是由一个真正的移动应用版本发出的。

这些移动操作系统API的目的是为开发者提供一种方法,让网络服务验证一个请求是在一个非越狱的设备上提出的,并带有一个合法的应用程序的应用商店实例。有趣的是,在这两种情况下,苹果和谷歌在文档中都有具体的语言,表明这些应该被用作应用程序完整性的提示,但不是保证。

BFF模式能解决客户端冒充问题吗?

BFF模式,是 "backend for frontend "的缩写,是运行一个后端服务来补充一个单页应用程序的想法。这种部署方式有多种变化,其中一些在基于浏览器的应用程序的OAuth规范草案中有所记载。

关于OAuth客户端的冒充,其关键区别在于,你的后端可以是OAuth客户端,可以使用客户端认证。如果后端持有令牌,而根本不向SPA发送令牌,那么令牌就不会泄露给冒充的应用程序。虽然这听起来不错,但你的后端无法保证向它发出的任何请求都是来自合法的SPA,所以问题只解决了一半。这确实使问题不那么严重,因为试图利用客户端冒名顶替的人不可能真正得到访问令牌本身,而只能欺骗后端用该访问令牌发出API请求。

客户端冒名顶替的未来解决方案

我提到这是在最近几次活动中OAuth社区内讨论的一个反复出现的主题。我在OAuth安全研讨会上发表了一篇关于移动应用中的客户端冒名顶替的演讲。这次会议没有被记录下来,但我把幻灯片贴在这里。在那次会议上,我提出了利用苹果和谷歌的应用证明API作为客户端认证形式的想法。在讲座后的讨论中,我们听到一个小组最近为一个客户实际实现了这一想法,这是对这一概念的一个很好的验证。另外,George Fletcher第二周的EIC2022会议上发表了一篇关于几乎相同主题的演讲。我很高兴看到这被认为是移动应用的需求。

就浏览器而言,我认为我们在寻找类似的解决方案方面还有很大的差距,因为浏览器与操作系统的结合程度不如移动应用。随着WebCrypto和WebAuthn等现代浏览器API的出现,我们有可能在未来看到类似的东西。

客户端冒名顶替是你应该关心的事情吗?这真的取决于你的情况,特别是你是否有任何政策将特定的公共客户与其他客户区别对待。