OAuth 是一个安全协议,用于保护全球范围内大量且不断在增长的web api,它用于连接不同的网站,还支持原生应用和移动应用于云服务之间的连接。
它是各个领域标准协议中的安全层。
1.OAuth 2.0是什么
OAuth 2.0 是一个授权协议,它允许应用软件代表(而不是充当)资源拥有者去访问资源拥有者的资源。应用向资源拥有者请求授权,然后得到令牌(token),并用它来访问资源。
这一切都不需要应用去充当资源拥有者的身份,因为令牌明确表示了授予的访问权。OAuth 令牌可以限制客户端只能执行资源拥有者授权的操作。
虽然 OAuth 基本上不关心它所保护的资源类型,但它确实很适合当今的restful web服务,也很适合web应用和原生应用。从小型单用户应用,到数百万用户的互联网api,它
都适用。在受控的企业环境中,它能对新一代内部业务api和系统访问进行管理,在它所成长起来的纷乱复杂的web环境中,它也能游刃有余的保护各种面向用户的api。
OAuth 的定义:
OAuth2.0 框架能让第三方应用以有限的权限访问http服务,可以通过构建资源拥有者与http服务间的许可交互机制,让第三方应用代表资源拥有者访问服务,或者通过
授予权限给第三方应用,让其代表自己访问服务。
作为一个授权框架,OAuth关注的是如何让一个系统组件获取另外一个系统组件的访问权限。在OAuth的世界中,最常见的情形是客户端应用代表资源拥有者(通常是终端用户)
访问受保护资源。到目前为止,我们需要关心如下组件:
1.资源拥有者有权访问api,并能将api访问权限委托出去。
2.受保护资源是资源拥有者有权限访问的组件,这样的组件形式有很多,大多数情况下是某种形式的web api,资源指的是这些api支持读,写和其他操作。
3.客户端是代表资源拥有者访问受保护资源的软件。OAuth中,只要软件使用了受保护资源上的api,它就是客户端。
整个系统的目标是:让客户端为资源拥有者访问受保护资源。
2.黑暗的旧时代:凭据共享与凭据盗用
1.复制用户的凭证并用它登录到另一个服务。
客户端首先得到用户的用户名和密码或者会话cookie,然后用它们访问受保护资源,假装是用户。受保护资源将客户端视为用户并直接通过身份认证,而实际上与受保护资源
建立连接的是客户端。这种方法要求用户在客户端和受保护资源端使用的是相同的凭证,使用这种凭证盗用技术只能在同一安全域内使用。也就是说,如果一个公司控制着客户端,
授权服务器和受保护资源,并且这些组件都在相同的策略和网络控制下运行,这种方法才行得通。这一技术还会将用户的密码暴露给客户端应用,即使在单一安全域中使用一组
凭据,这也基本上无法避免。无论如何,客户端是在扮演用户,受保护资源无法区分资源拥有者和扮演资源拥有者的客户端,因为二者都以同样的方式使用相同的用户名和密码。
2.如果两个服务位于不同安全域中,可以采用向用户索要。移动应用让用户输入用户名和密码,然后直接将这些凭据通过网络发送给后端api。为了可以持续访问api,客户端应用
会保存用户的凭证,以便在必要的时候访问受保护资源。这种做法极其危险,因为一旦任何一个正在使用的客户端被攻破,就意味着该用户在所有的系统中的账户都被攻破。
在极少数的情况下,这种方法是可行的:客户端需要直接获取用户的凭据,并且能在用户不在场的情况下降这些凭据用于服务。这排除了多种用户登录方式,包括几乎所有的
联合登陆系统,很多多因素身份认证登录系统,以及大多数高安全等级的登录系统。
有趣的是,这恰恰就是LDAP(轻量级目录访问协议)这样的密码身份认证技术使用的模式。在使用LDAP进行身份认证的时候,客户端应用直接从用户那里获取凭据,然后通过
LDAP服务器检验它们是否有效。客户端系统在这个处理过程中必须得到用户的明文密码,否则无法向LDAP服务器验证密码的正确性。从本质上说,这就是针对用户的中间人攻击,
虽然通常是善意的。
只要采用这种方式,就会将用户最重要的凭据暴露给可能并不信任的应用---客户端。为了能一直充当用户,客户端就不得不以一种可重现的形式(通常是明文或者某种可逆的
加密机制)存储用户的密码,用于后续继续访问受保护资源。如果客户端应用被攻破,攻击者不仅能访问客户端,还能访问受保护资源以及用户使用的其他具有相同密码的服务。
而且,在以上这些方法中,客户端应用充当资源拥有者,受保护资源无法分辨出哪个调用是由资源拥有者直接发起的,还是由客户端代发的。你不能随时解除它的权限。阻止流氓
行为的唯一方法就是修改密码,让打印服务之前保存的密码失效。更糟糕的是,很多用户都喜欢在不同的系统中使用相同的密码,这可能导致所有关联账户都受到牵连。
3.还可以授予打印服务全局的访问权限,使它能够代表它指定的任何用户病访问存储服务上的所有照片。常用的方式是为客户端颁发一个开发者密钥,让客户端使用该密钥直接
调用受保护资源。在这种方法中,开发者密钥是一个全局的密钥,客户端可以用它来充当任意一个由其指定的用户,用户的指定很可能通过一个api参数来完成。这样做的好处是
避免了向客户端暴露用户凭据,但代价是要向客户端提供强大的开发者密钥。有了这个密钥实际上拥有了自由访问受保护资源的权利,这在一定程度上是可行的,但前提是受保护
资源充分了解并信任客户端。但是这样的关系几乎不可能存在于两个组织之间。
4.还有一种方法是给用户一个特殊的密码,此密码仅用于透露给第三方服务。用户自己不会使用这个密码来登录,只是将它黏贴到所使用的第三方应用里。用户不再需要向客户端
透露登录密码,受保护资源也不再需要相信客户端时刻都能代表所有用户执行正确的操作。但是,这种系统的可用性并不好。它要求用户除了管理好自己的主密码之外,还要创建,
分发和管理特殊的凭据。因为需要用户来管理这些凭据,所以一般来说,客户端与凭据本身并没有什么对应关系。这使得撤销某个具体的应用的访问权限变得比较困难。
如果能为每个客户端和每个用户的组合分别颁发这种对受保护资源具有受限访问权限的凭据会怎么样?如此一来,就可以将受限访问的权限分别与这些受限的凭据绑定。更进一步,
如果有一个基于网络协议,能够部署到整个互联网上,跨安全边界的生成并安全的分发这些受限的凭据,同时拥有良好的用户体验,又会怎样?
3.授权访问
OAuth协议的设计目的是:让最终用户通过OAuth将他们在受保护资源上的部分权限委托给客户端应用,使客户端应用代表他们执行操作。为实现这一点,OAuth在系统中引入另外
一个组件:授权服务器。
受保护资源依赖授权服务器向客户端颁发专用的安全凭证---OAuth访问令牌。为了获取令牌,客户端首先将资源拥有者引导至授权服务器,请求资源拥有者为其授权。授权服务器先
对资源拥有者进行身份认证,然后一般会让资源拥有者选择是否对客户端授权。客户端可以请求授权功能或权限范围的子集,该子集可能会被资源拥有者进一步缩小。一旦授权请求被许可,
客户端就可以向授权服务器请求访问令牌。按照自营拥有者的许可,客户端可以使用该令牌对受保护资源上的api进行访问。
在这个过程中,没有将资源拥有者的凭证暴露给客户端:资源拥有者向授权服务器进行身份认证的过程中所用的信息是独立于客户端交互的。客户端没有强大的功能的开发者密钥,无法
随意访问任何资源,而是必须在得到有效的资源拥有者授权之后才能访问受保护资源。虽然大多数OAuth客户端可以向授权服务器进行身份认证,但仍然需要得到授权后才能访问资源。
用户通常不必查看或直接处理访问令牌。OAuth不需要由用户生成令牌并黏贴到客户端,而是简化了这一过程:客户端请求令牌,用户对客户端授权。然后由客户端管理令牌,用户管理
客户端应用。
3.1.超越HTTP 基本认证协议和密码共享反模式
上节中列出的许多'传统'方法都是密码反模式,它们通过共享机密信息(密码)来直接代表当事方(用户)。用户通过与应用共享密码,使应用能够访问受保护的api。然而,这种存在
很多问题。密码本身可能被盗用或者被猜到;同一个用户在不同的服务上使用完全相同的密码;为了后续能继续访问api而保存密码使得密码更容易被盗。
http api最开始是如何引入密码保护功能的?我们可以从http协议的历史及其安全手段看出端倪。http协议制定了一个机制,用户可以凭借该机制在浏览器中使用用户名和密码向
一个网页进行身份认证,这就是所谓的http基本认证(HTTP basic auth)。还有一种更安全的认证协议,叫做http摘要(HTTP digest auth)。但就是我们的目的来说,它们没有
什么区别,因为它们都假设用户在场,并且向http服务器呈递用户的用户名和密码。此外,由于http是一个无状态的协议,因此每一个http事务都要呈递这些凭证。
鉴于http原本是一个文档协议,这一切都是合理的。作为一个协议,http不会区分一个事务是由用户通过浏览器发起的,还是通过其他软件发起的。这种基本的灵活性是http协议
得到普及的关键。但结果是,除了面向用户的(网页)服务之外,当http开始被用于直接访问api时,其现有的安全机制顺理成章的被沿用到新的应用场景中。这个不明智的技术决策
导致了一种长期存在的错误做法:为api何网页服务不断的呈现密码。虽然浏览器可以使用cookie或者其他会话管理技术,但是访问web api的http客户端没有这样的机制可用。
OAuth从一开始就被设计成一个用户api的协议,其中最主要的交互过程都是在浏览器之外进行的。OAuth的整个流程通常是由最终用户在浏览器中启动的,实际上这也正是对委托
模式的灵活性和优势所在。但是最终接受令牌的,使用令牌访问受保护资源的步骤是对用户不可见的。实际上,OAuth的一些主要事务过程都发生在用户不在场的情况下,客户端仍然
能够代表用户执行操作。OAuth让我们摈弃http基本协议中的观念和假设,将一种功能强大,安全的方式引入先进的api体系中。
3.2.授权委托:重要性及应用
委托概念是OAuth功能强大的根基。虽然OAuth经常被称作授权协议,但它也是一个委托协议。通常,被委托的是用户权限的子集,但是OAuth本身并不承载或者传递权限。相反,
它提供了一种方法,让客户端可以请求用户将部分权限委托给自己。然后,用户可以批准这个委托请求。被批准之后,客户端就可以去执行那些操作了。
在这里,委托协议和授权协议的区别很重要,因为OAuth令牌中携带的授权信息对系统中的大部分组件是不透明的。只有受保护资源需要了解授权信息,只要它能从令牌中得知
授权信息(既可以直接从令牌中获取,也可以通过某种服务来获取),它就可以按照要求提供api服务。
3.3.用户主导的安全与用户的选择
由于OAuth的委托过程需要资源拥有者的参与,因此它提供了一种在很多其他安全模式中不存在的可能性:重要的安全决策可以由最终用户来决定。传统上,安全决策一直由集权机构
负责。由集权机构决定谁可以使用服务,使用什么客户端以及何种目的使用。OAuth则允许集权机构将某些决定权交给最终使用软件的用户手中。
OAuth系统通常遵循TOFU原则:首次使用时信任(trust on first use)。在TOFU模型中,需要用户在第一次运行时进行安全决策,而且并不为安全决策预设任何先决条件或配置,
仅提示用户做出决策。这个过程可以简单到只是询问用户'要连接新应用吗'。当然,很多实现允许在这个步骤中进行更多的控制。无论用户遇到的是哪种情况,只要具有相应的权限,
他们就能够做出安全决策。系统会记住用户的决策,以便以后使用。换句话说,只要首次建立了授权关系,系统就会在后续的处理过程中继续信任用户的决策:首次使用时信任。
TOFU是强制要求吗?
OAuth实现并不强制要求采用TOFU方法管理安全机制,但是这2种技术经常结合使用。这是为什么呢?因为要求用户在一个上下文环境中做出安全决策具有很强的灵活性,而不断地
要求用户做决策会让人疲惫,TOFU方法在这两者间实现了良好的平衡。如果从TOFU中去掉'信任'部分,委托就无从谈起。如果去掉'首次使用'的部分,则用户将会很快因为无休止的
访问请求变得麻木。这种由安全系统造成的疲惫会引起工作的懈怠,这比安全系统原本要解决的安全问题更加危险。
这种方法还可以让用户从功能而不是安全性的角度做出决策:'是否允许客户端执行它请求的操作?'这是与传统安全模型的一个重要区别。在传统安全模型中,决策者需要提前限定
哪些行为是不允许的,而这样的安全决策通常会令普通用户不知所措。无论如何,用户更关心的是他们想要完成的任务,而不是试图阻止哪些事情。
但这并不是说TOFU必须用于所有的事务或决策。实际上,安全架构师可以采用3层名单机制,它具有很强的灵活性。
由白名单确定已知的良好和受信任的应用,由黑名单确定已知的不良应用或者其他糟糕的参与者。这些决策很容易根据系统决策作出,而不需要最终用户参与。
在传统的安全模型中,因为任何不在名单里的内容会默认自动归入黑名单。然后,如果使用TOFU,就可以在上述的两个名单之间增加一个灰名单,在这个名单中,会优先考虑用户在
运行时做出的信任决策。会有一定的策略来记录和审查这些用户决策,以使风险最小化。通过灰名单机制,系统的可扩展性得到了极大的提升,同时又不牺牲安全性。
4.OAuth 2.0:优点、缺点和丑陋的方面
OAuth2.0非常善于获取用户的委托决策,并通过网络传递出去。它允许多方参与安全决策过程,尤其是在运行期间让最终用户参与决策。它是由多个可移动的组件构成的协议,但是在很多
方面它都比其他方案更简单,更安全。
OAuth的设计中有一个重要的假设,就是不受控制的客户端总是比授权服务器或者保护资源多出好几个数量级。这是合理的,因为单个授权服务器可以很轻松的保护多个资源服务器,并且
很有可能有许多不用类型的客户端想要访问特定的api。一台授权服务器甚至可以有多个不同的客户端信任等级。这样的架构导致的结果是,尽可能将复杂性从客户端移到服务端。这对于客户端
开发人员来说是好事,因为客户端成了系统中最简单的部分。客户端开发人员不再需要像在先前的安全协议中那样,处理签名规范化以及解析复杂的安全策文档,也不需要担心处理敏感的用户
凭证。OAuth令牌提供了一种比密码略复杂的机制,如果使用得当,其安全性比密码要高很多。
另一方面,授权服务器和受保护资源要承当更多的复杂性和安全性方面的责任。客户端只要保护好自身的客户端凭证和用户令牌即可,单个客户端被攻破造成的损害,但只有该客户端的用户
受到影响。被攻破的客户端也不会泄露资源拥有者的凭据,因为客户端根本没有机会接触到这些凭据。然后,授权服务器则需要管理和保护系统中所有客户端和用户的凭据和令牌。虽然这确实
使得它更容易成为攻击目标,但是保护单个授权服务器比保护上千上万台由不同的开发人员开发的客户端容易的多。
OAuth2.0的可扩展性和模块化是其最大的优势之一,因为这使得该协议适用于各种环境。然后,正是这种灵活性导致不同的实现之间存在根本性的兼容性问题。当开发人员想在不同的系统
上实现OAuth时,它提供的众多自定义选项容易使人困惑。
更糟糕的是,OAuth的某些自定义选项可能会被用在错误的地方或者使用不当,而导致不安全的实现。
5.OAuth 2.0 不能做什么
由于OAuth被定义为一个框架,对于OAuth是什么和不是什么,一直未明确。
1.OAuth没有定义http协议之外的情形
由于使用bearer令牌的OAuth2.0并不提供消息签名,因此不应该脱离https使用。机密信息需要在网络上传播,所以OAuth需要tls注意的传输机制来保护这些信息。有一个标准定义了
如何在简单认知与安全层(SASL)之上使用OAuth令牌,也有在受限应用协议(CoAP)之上使用OAuth的新尝试,未来还可能出现使用OAuth的部分处理过程运行在非TLS链接之上的尝试。但
即便如此,在使用其他协议和系统时,也需要有一个明确的机制来承担https事务所承担的任务。
2.OAuth不是身份认证协议
虽然可以用它构建一个。尽管用户确实存在,但OAuth事务本身并不透露关于用户的信息。想一想照片打印的例子:照片打印服务不需要知道用户是谁,只需要有人告诉他可以下载照片即可。
OAuth本质上只是一个部件,能用于更宏大的技术方案中提供其他功能。另外,OAuth在多个地方用到了身份认证,最典型的就是资源拥有者和客户端软件要向授权服务器进行身份认证。但这种
内嵌身份证的行为并不会使得OAuth自身成为身份认证协议。
3.OAuth没有定义用户对用户的授权机制
尽管它在根本上是一个用户向软件授权的协议。OAuth假设资源拥有者能够控制客户端。要使资源拥有者向另外一个用户授权,仅使用OAuth是不行的。但这种授权并不罕见,User Managed
Access协议就是为此诞生,它规定了如何使用OAuth构建一个支持用户对用户授权的系统。
4.OAuth没有定义授权机制处理
OAuth提供了一种方法来传达授权委托已发生这一事实,但是它并不定义授权的内容。相反,由服务api定义的权限范围,令牌之类的OAuth组件来定义一个给定的令牌适用于哪些操作。
5.OAuth没有定义令牌格式
实际上,OAuth协议明确声明了令牌的内容对客户是完全不透明的。这不同于之前的一些安全协议,如WS-*,安全断言标记语言(SAML)和Kerberos,这些协议都要求客户端应用能够解析并处理
令牌。但是,颁发令牌的授权服务器和接收令牌的受保护资源扔需要理解令牌。这个层面的互操作性要求催生了JSON Web Token(JWT)格式和令牌内省协议。虽然令牌本身对客户端还是不透明,
但现在它的格式能被其他组件理解。
6.OAuth2.0没有定义加密方法
这与OAuth1.0不同,OAuth2.0没有定义新的加密机制,而是允许借用通用的加密机制,这些加密机制不止适用于OAuth。这种有意的遗漏催生了JSON对象签名和加密(JOSE)规范套件,该套件
提供了一系列通用的加密机制,可以配合OAuth使用,也可以脱离OAuth使用。
7.OAuth2.0不是单体协议
该规范被分成了多个定义和流程,每个定义和流程都有各自适用的场景。某种程度上,可以将OAuth2.0视为一个安全协议生成器,因为它可用于为许多不同的应用场景设计安全架构。
不同OAuth流程之间的代码复用:
虽然OAuth的应用种类繁多,但在迥异的应用之间能够复用大量的代码,而谨慎的应用OAuth协议还可以促进其未来的发展并增强灵活性。例如,假设有2个后端系统需要安全的交互,但不涉及
具体特定用户,比如进行批量数据传输。用传统的开发者密钥就能够完成这个任务,因为客户端和资源都在同一个受信任的安全域中。但是,如果系统使用OAuth客户端凭证许可,那么系统可以
限制令牌的生命周期和访问权限,开发人员则可以在客户端和受保护资源使用现有的OAuth库和框架,而不用去搞一套完全自定义的东西。由于受保护资源能够处理受OAuth令牌保护的请求,
因此当未来某个时刻受保护资源希望以每个用户授权的方式提供数据服务时,它就可以很容易的同时支持这两种访问方式。例如,可以为批量传输的数据和用户专门的数据设置不同的权限范围,
这样只需要对代码稍加修改,受保护资源就可以轻松区分这2种调用。
OAuth无意用一个大而全的协议去解决安全系统所有方面的问题,而是只专注于一件事情,把剩下的问题留给其他组件。
6.小结
1.OAuth关注的是如何获取令牌和如何使用令牌
2.OAuth是一个委托协议,提供跨系统的授权方案
3.OAuth用可用性和安全性更高的委托协议取代了密码共享反模式
4.OAuth专注于很好的解决小问题,因而是整个安全系统中一颗很合适的螺丝钉