|
什么是 OAuth 2.0,您为什么要关心它? 贾斯汀·里奇 (Justin Richer) 和安东尼奥·桑索 (Antonio Sanso) 在这篇摘自 OAuth 2 in Action 的文章中,我们将向您介绍 OAuth 2.0 并讨论它的重要性。 |
如果您现在是 Web 上的软件开发人员,您很可能听说过 OAuth。它是一种安全协议,用于保护全世界大量(并且还在不断增加)的 Web API,从 Facebook 和 Google 等大型提供商到初创公司和企业内部的小型一次性 API。它用于将网站相互连接起来,并为连接到云服务的本机和移动应用程序提供支持。它被用作各种领域中越来越多的标准协议的安全层,从医疗保健到身份,从能源到社交网络。 OAuth 无疑是当今网络上占主导地位的安全方法,它的无处不在为希望保护其应用程序的开发人员提供了公平的竞争环境。
但它是什么,它是如何工作的,我们为什么需要它?在本文中,我们将探讨这些问题。
什么是 OAuth 2.0?
OAuth 2.0 是一种委托协议 ,一种让控制资源的人允许软件应用程序代表他们访问该资源而不冒充他们的方法。客户端通过请求资源所有者的授权并接收可用于访问资源的 令牌 来执行此操作。这一切都在客户端应用程序不需要模拟资源所有者的情况下发生,因为令牌明确表示委托的访问权限。在许多方面,您可以将 OAuth 令牌视为网络的“代客钥匙”。汽车的代客钥匙允许车主将有限的访问权限授予代客,而无需以车主钥匙的形式移交完全控制权。简单的代客钥匙将代客限制为只能使用点火装置和车门,但不能使用行李箱或杂物箱。更复杂的代客钥匙可以限制汽车的最高速度,甚至可以在汽车从起点行驶超过设定距离时关闭汽车,向车主发出警报。以几乎相同的方式,OAuth 令牌可以将客户端的访问限制为仅资源所有者已委托的操作。
例如,假设您有一个云照片存储服务和一个照片打印服务,并且您希望能够打印存储在您的存储服务中的照片。幸运的是,您的云存储服务有一个 API,打印服务知道如何与之对话。这很好,只是这两项服务由不同的公司运营,这意味着您的存储服务帐户与您的打印服务帐户没有关联。我们可以使用 OAuth 来解决这个问题,方法是让您在不同的服务中委托对您的照片的访问。
虽然 OAuth 在很大程度上不知道它保护的是哪种资源,但它确实非常适合当今的 RESTful Web 服务,并且它适用于 Web 和本机客户端应用程序。它可以从小型单用户应用程序一直扩展到数百万用户的互联网 API。它就像在网络的未驯服的荒野中成长一样,就像它在企业的受控和监视边界内一样。
这还不是全部:如果您在过去五年中使用过移动或网络技术,那么您实际使用 OAuth 将您的权限委托给应用程序的可能性会更高。如果您曾经使用过 Facebook 应用程序或使用 Google 登录过网站,那么您就使用过 OAuth。还有很多情况下 OAuth 协议的使用是完全透明的,例如它在 Steam 和 Spotify 的桌面应用程序中的使用。除非最终用户正在寻找 OAuth 事务的明显标志,否则永远不会知道它正在被使用。这当然是一件好事,因为一个好的安全系统在一切正常运行时应该几乎是看不见的。
我们知道OAuth是一个安全协议,但是它到底有什么作用呢?由于您正在阅读一篇据称是关于 OAuth 2.0 的文章,所以这是一个公平的问题。根据定义它的规范:
OAuth 2.0 授权框架允许第三方应用程序获得对 HTTP 服务的有限访问权限,或者代表资源所有者通过编排资源所有者和 HTTP 服务之间的批准交互,或者允许第三方应用程序代表自己获取访问权限。
让我们稍微解释一下:作为一个授权框架,OAuth 就是获得从系统的一个组件到另一个组件的访问权。特别是,在 OAuth 世界中,客户端应用程序希望代表资源所有者(通常是最终用户)访问受保护的资源。这些是我们到目前为止的组件:
目标是代表资源所有者将客户端连接到受保护的资源。在我们的打印示例中,假设您已将度假照片上传到照片存储站点,现在您想要打印它们。存储站点的 API 是资源,打印服务是该 API 的客户端。作为资源所有者,您需要能够将您的部分权限委托给打印机,以便它可以读取您的照片。您可能不希望打印机能够读取您的所有照片,也不希望打印机能够删除照片或上传自己的新照片。但是,归根结底,您感兴趣的是打印照片,如果您像大多数用户一样,就不会考虑用于完成此操作的系统的安全架构。
很可能您与大多数用户不同,您实际上关心安全架构。在下一节中,我们将了解如何在没有 OAuth 的情况下不完美地解决这个问题,然后我们将了解 OAuth 如何更好地解决它。
糟糕的过去:凭证共享(和凭证盗窃)
想要连接多个不同的服务的问题并不是什么新鲜事,并且可以提出一个令人信服的论点,即从世界上出现不止一个网络连接服务的那一刻起,这个问题就已经存在了。
一种在企业领域流行的方法是 复制用户的凭据并在另一项服务上重放它们 。
在这种情况下,照片打印机假定用户在打印机上使用的凭据与他们在存储站点上使用的凭据相同。当用户登录打印机时,打印机只是简单地重放存储站点上的用户用户名和密码,以便假装是用户访问那里的用户帐户。
在这种情况下,用户需要使用某种凭据向客户端进行身份验证,这些凭据通常由客户端和受保护资源集中控制并达成一致。然后客户端获取该凭据,例如用户名和密码或域会话 cookie,并将其重放回受保护的资源,假装是用户。受保护资源的行为就好像用户刚刚直接进行了身份验证一样,这实际上确实按照上述要求在客户端和受保护资源之间建立了连接。
这种方法要求客户端和受保护的资源使用相同的凭据进行身份验证,这将这种凭据盗窃技术的有效性限制在单个安全域中。
如果这两个服务位于不同的安全域中,就像在我们的照片打印示例中一样?面对这一挑战,这些可能的凭据窃贼可能会采用一种古老的方法来窃取某些东西:只 问用户 。如果打印服务想要获取用户的照片,它可以提示用户输入照片存储站点上的用户名和密码。
就像以前一样,打印机在受保护的资源上重放这些凭据并模拟用户。在这种情况下,用户用于登录客户端的凭据可能与在受保护资源上使用的凭据不同。但是,客户端只是要求用户提供受保护资源的用户名和密码。 事实上,许多用户在承诺涉及受保护资源的有用服务时会这样做 ,这是当今移动应用程序访问用户帐户的最常见方法之一。
然而,这种方法仍然只在非常有限的情况下有效:客户端需要直接访问用户的凭据,并且这些凭据需要能够针对用户不在场的服务进行重放。这排除了多种凭证类型,包括几乎所有的联合登录和更高安全性的登录。
对于它确实起作用的那些情况,它会将用户的主要凭据暴露给可能不可信的应用程序,即客户端。为了继续充当用户,客户端必须以可重放的方式(通常以明文或可逆加密机制)存储用户密码,供以后在受保护资源上使用。如果客户端应用程序遭到破坏,攻击者不仅可以访问客户端,还可以访问受保护的资源,以及最终用户可能使用相同密码的任何其他服务。
此外,在这两种方法中,客户端应用程序都在 模拟 资源所有者,并且受保护的资源无法区分直接来自资源所有者的调用和通过客户端定向的调用。为什么这是不受欢迎的?让我们回到我们的打印服务示例。在有限的情况下,许多方法都可行,但考虑到您不希望打印服务能够从存储服务上传或删除照片,只需读取您想要打印的照片即可。此外,您希望它只能在您想要打印照片时读取,并且您希望能够随时关闭该访问权限。但是,如果打印服务需要冒充您来访问您的照片,则存储服务无法判断是打印机还是您要求执行某些操作。
如果打印服务偷偷在后台复制您的密码(即使它承诺不会),它可以假装是您并在需要时抓取您的照片。关闭流氓打印服务的唯一方法是更改存储服务的密码,在此过程中使他们的密码副本无效。再加上许多用户在不同系统中重复使用密码这一事实,您还有另一个地方可以窃取密码和相互关联的帐户。
到目前为止,我们已经看到重放用户密码是不好的。如果我们让打印服务代表它选择的任何人访问存储服务上的所有照片,会怎么样?另一种常见的方法是 使用发给客户端的开发人员密钥 ,客户端使用它来直接调用受保护的资源。
在这种方法中,开发人员密钥充当一种通用密钥,允许客户端模拟它选择的任何用户,可能是通过 API 参数。这样做的好处是不会将用户的凭据暴露给客户端,但代价是客户端需要非常强大的凭据。我们的打印服务可以随时为任何用户打印它想要的任何照片,因为客户实际上可以自由支配受保护资源上的数据。这可以在一定程度上起作用,但只能在单个安全域内起作用,在该安全域中,客户端可以完全了解并信任受保护的资源。跨两个组织建立任何此类关系的可能性微乎其微,例如我们的照片打印场景中的那些组织。此外,如果客户端的凭据被盗,对受保护资源造成的损害可能是灾难性的,因为存储服务的所有用户都会受到漏洞的影响,无论他们是否使用过打印机。
我们不能做得更好吗?
保护对 Web API 的委派访问
另一种可能的方法是为用户提供一个仅用于与第三方服务共享的密码。
这开始接近一个理想的系统,因为用户不再需要与客户端共享他们的真实密码,受保护的资源也不需要隐含地信任客户端始终代表所有用户正确操作。然而,这样一个系统的可用性本身并不是很好。这需要用户生成、分发和管理这些特殊凭证,以及他们已经必须管理的主密码。由于必须由用户管理这些凭据,因此一般来说,客户端程序与凭据本身之间也没有关联。这使得撤销对特定应用程序的访问变得困难。
如果我们能够拥有一个有限的凭证,为每个客户端和每个用户组合单独颁发,用于受保护的资源,会怎样?然后,我们可以将有限的权利绑定到这些有限的凭据中的每一个。更重要的是,如果有一种基于网络的协议允许以用户友好且可扩展到整个 Internet 的方式跨安全边界生成和安全分发这些有限的凭据会怎么样?
OAuth 是一种旨在执行此操作的协议:在 Web 授权协议 OAuth 中,最终用户将他们访问受保护资源的部分权限 委托 给客户端应用程序以代表他们行事。为了实现这一点,OAuth 在系统中引入了另一个组件:授权服务器:
授权服务器 (AS) 受到受保护资源的信任,可以向客户端颁发特殊用途的安全凭证(称为 OAuth 访问令牌 )。为了得到这个令牌,客户端首先将资源所有者发送给授权服务器,以请求资源所有者授权这个客户端。用户向授权服务器进行身份验证,通常会选择是否授权发出请求的客户端。客户端能够要求用户可以进一步减少的功能或范围的子集。一旦获得授权,客户端就可以向授权服务器请求访问令牌。此访问令牌可用于受保护的资源以访问 API,如资源所有者授予的那样。
在此过程中,资源所有者的凭据绝不会暴露给客户端:资源所有者向授权服务器进行身份验证,与用于向客户端进行身份验证的任何内容分开。客户端也没有强大的开发人员密钥:虽然大多数 OAuth 客户端都有自己的客户端凭据集,但在这个典型的 OAuth 过程中,客户端无法自行访问任何内容。相反,它必须先获得有效资源所有者的授权,然后才能访问任何受保护的资源。
此外,用户通常不必直接查看或处理访问令牌。 OAuth 协议不是要求他们生成令牌并将它们粘贴到客户端,而是促进了此过程,并使客户端请求令牌和用户授权客户端变得相对简单。然后客户可以管理令牌,用户可以管理客户端应用程序。
OAuth 2.0:好的、坏的和丑陋的
OAuth 2.0 非常擅长捕捉用户授权决定并通过网络表达。它允许多方参与安全决策过程,尤其是运行时的最终用户。
OAuth 2.0 设计中的一个关键假设是,与授权服务器或受保护资源相比,在野外的客户端总是多几个数量级。因此,社区决定尽可能将复杂性从客户端转移到服务器上。这对于不再需要处理签名规范化或解析复杂的安全策略文档的客户端开发人员来说非常有用。 OAuth 令牌提供的机制仅比密码稍微复杂一点,但如果使用得当,则安全得多。
然而,另一方面是授权服务器和受保护的资源现在要对更多的复杂性和安全性负责。客户端只需要管理自己的凭据和令牌的安全,单个客户端的破坏虽然很糟糕,但损害有限。另一方面,授权服务器需要管理和保护系统上所有客户端和所有用户的凭据和令牌。虽然这确实使其更容易成为攻击目标,但与让独立开发人员编写的一千个客户端同样安全相比,使单个授权服务器高度安全要容易得多。
OAuth 2.0 的可扩展性和模块化是其最大的优势之一,因为它允许该协议在各种环境中使用。然而,同样的灵活性会导致实现之间存在基本的不兼容问题。 OAuth 留有许多部分是可选的,这会使试图在两个系统之间实现它的开发人员感到困惑。
更糟糕的是,OAuth 中的某些可用选项可能会在错误的上下文中使用或未正确执行,从而导致不安全的实施。可以这么说,仅仅因为一个系统实现了 OAuth,甚至根据规范正确地实现了它,并不意味着这个系统在实践中实际上是安全的。
最终,OAuth 2.0 是一个非常好的协议,但它远非完美,当然也不是万灵药。我们将在未来的某个时候看到它的替代品,就像技术领域的所有事物一样,但在撰写本文时还没有出现真正的竞争者。 OAuth 2.0 的替代品很可能最终成为 OAuth 2.0 本身的配置文件或扩展。
OAuth 不是什么
OAuth 用于许多不同类型的 API 和应用程序,以前所未有的方式连接在线世界。尽管它正在接近无处不在,但有很多东西是 OAuth 所 没有的 ,在理解协议本身时理解这些界限很重要。
-
OAuth 没有在 HTTP 协议之外定义。
-
OAuth 不是身份验证协议(尽管它可用于构建一个)。
-
OAuth 没有定义用户到用户委托的机制。
-
OAuth 没有定义授权处理机制。
-
OAuth 2.0 没有定义令牌格式。
-
OAuth 2.0 没有定义加密方法。
-
OAuth 2.0 也不是一个单一的协议,而是一个定义一系列相关协议的框架。
OAuth 2.0 并没有试图成为一个解决安全系统所有方面问题的单一协议,而是专注于一件事,并为其他组件留出空间,让它们在更有意义的地方完成自己的工作。虽然 OAuth 有很多不具备的地方,但 OAuth 确实提供了一个坚实的基础,其他专注的工具可以在此基础上构建更全面的安全架构设计。
概括
OAuth 是一种广泛使用的安全标准,它支持以对 Web API 友好的方式安全访问受保护的资源。
-
OAuth 是一种委托协议,提供跨系统的授权
-
OAuth 将密码共享反模式替换为同时更安全、更可用的委托协议
-
OAuth 专注于解决一小部分问题并很好地解决它们,这使其成为大型安全系统中的合适组件
有关 OAuth 2 协议的更多信息,包括动手指导和从头到尾构建 OAuth 系统的练习,请查看 Manning Publications 的新书 OAuth 2 In Action 。