OAuth 2.0 授权框架 RFC6749翻译

最近要设计开放平台,调研时发现很多开放平台都是基于OAuth 2.0的,于是来学习一下文档。顺带翻译一遍。

原文:https://datatracker.ietf.org/doc/html/rfc6749


OAuth 2.0授权框架

摘要

OAuth 2.0授权框架(Authorization Framework)使一个第三方应用能够受限地访问一个HTTP服务,可能是代表资源所有者去和HTTP服务进行一些交互,也可能是第三方应用自己需要访问。本规范取代并废除RFC 5849中描述的OAuth 1.0协议。

1 介绍

在传统的 客户端-服务器 授权模型中,客户端使用资源所有者的凭据(credentials)来请求服务器上一个访问受限的资源(或说受保护的资源)。为了提供让第三方应用能够访问受限资源,资源所有者得将自己的凭据分享给第三方。这里有很多问题和限制:

  • 第三方应用得保存用户的凭据以备未来使用,凭据典型地是明文的密码
  • 服务器需要提供密码授权,尽管密码授权自身安全性就很弱。
  • 第三方应用获得了对于资源所有者的受保护资源的过宽的访问权,资源所有者没有办法控制访问的时长以及范围。
  • 资源所有者如果想禁止其中一个第三方应用的访问的话,必须修改密码,但这样又导致其他第三方也一起无法访问了。
  • 如果其中一个第三方应用没有保存好用户的密码,那密码所保护的数据就全泄漏了。

OAuth通过引入一个授权层并区分开资源所有者和客户端的角色,解决了这些问题。在OAuth中,客户端请求访问存储在资源服务器上并由资源所有者控制的资源,并获得与资源所有者不同的一组凭据。

客户端不需要使用资源所有者的凭据来访问受保护资源,它会获得一个访问令牌(access token) – 访问令牌是一个字符串,代表着指定的范围、生命周期和其他访问属性。 访问令牌们在资源所有者的许可下,由一个授权服务器分发给第三方客户端们。客户端使用访问令牌来访问存储在资源服务器上受保护的资源。

例如,一个终端用户(资源所有者)可以授权一个打印服务(客户端)访问她存储在一个照片分享服务(资源服务器)上受保护的照片,并且不需要给打印服务提供她的用户名和密码。她直接通过照片分享服务信任的一个服务器(授权服务)来进行授权,这服务器会分发打印服务专用委托凭证(访问令牌)。

这篇规范在设计上是和HTTP([RFC2616])一起使用的。在其他协议上使用OAuth不在考虑范围内。

OAuth 1.0协议([RFC5849])作为信息性文件发布,是一个小型社区的努力结果。本标准跟踪规范基于OAuth 1.0部署经验,以及从更广泛的IETF社区收集的其他用例和扩展性需求。OAuth 2.0协议与OAuth 1.0不向后兼容。这两个版本可能在网络上共存,实现可能会选择同时支持这两个版本。然而,本规范的目的是,新的实现应支持本文档中指定的OAuth 2.0,而OAuth 1.0仅用于支持现有部署。OAuth 2.0协议与OAuth 1.0协议的实现细节几乎不相通。熟悉OAuth 1.0的实现人员在使用本文档时不应该对结构和细节做任何假设。

1.1 角色

OAuth定义了四个角色:

  • 资源所有者(resource owner): 能够授权访问一个受保护资源的实体。当资源所有者是一个人时,称其为终端用户(end-user)。
  • 资源服务器(resource server): 存放受保护资源的服务器,能够接受使用访问令牌对受保护资源的访问请求并进行答复。
  • 客户端:一个使用它自己的授权,代表资源所有者请求受保护资源的应用。术语“客户端(client)”没有暗示任何特别的实现特性(例如,应用是不是执行在一个服务器、桌面还是其他设备上)。
  • 授权服务器(authorization server): 这个服务器在认证资源访问者并获得授权后会分发访问令牌给客户端。

这篇文章不涉及授权服务器和资源服务器之间的交互。授权服务器和资源服务器可能是同个服务器,也可能是分开的。一个授权服务器也可以分发由多个资源服务器认可的访问令牌。

1.2 协议流程

抽象的协议流程
图1:抽象的协议流程

图1中阐述的抽象的OAuth 2.0流程描述了四个角色间的交互,包含以下步骤:

A. 客户端从资源所有者处请求授权。授权请求可以直接向资源所有者发出(如图所示),或者最好是通过作为中间层的授权服务器间接发出。
B. 客户端收到授权许可(authorization grant),即一个代表资源所有者授权的凭证,使用这篇规范中描述的四个许可(grant)之一或者扩展许可类型来表达。授权许可类型取决于客户端用来请求授权时使用的方法以及授权服务器支持的类型。
C. 客户端通过与授权服务器进行认证并提供授权许可以请求一个访问令牌。
D. 授权服务器认证客户端并验证授权许可,如果有效,就会分发一个访问令牌。
E. 客户端通过提供访问令牌从资源服务器进行认证并请求受保护的资源。
F. 资源服务器验证访问令牌,如果有效,就会服务这个请求。
客户端从资源所有者获取授权许可(即步骤1和2描述的)的推荐方法是使用授权服务器作为中间层,后面有描述。

1.3 授权许可

授权许可是代表资源所有者的授权(来访问他受保护的资源)的一个凭证,给客户端用来获得访问令牌。这篇规范定义了四种许可类型 – 授权码(authorization code)、隐式(implicit)、资源所有者密码凭证和客户端凭证 – 以及一个可以定义额外类型的扩展机制。

1.3.1 授权码

授权码通过使用授权服务器作为客户端和资源所有者的中间层来获取。客户端指引资源所有者到一个授权服务器上(经由[RFC2616]中描述的它的用户代理),授权服务器反过来再指引资源所有者带着授权码跳回客户端,这样客户端就不用直接从资源所有者处获取授权了。

授权服务器在指引资源所有者带着授权码跳回客户端之前,认证了资源所有者并获得了授权。由于资源所有者只直接与授权服务器进行授权,资源所有者的凭证永远不用分享给客户端。

授权码提供了一些重要的安全性,比如能够认证客户端,以及访问令牌会直接传输给客户端而不用经由资源所有者的用户代理来传输并可能暴露给其他人,其他人包括资源所有者。

1.3.2 隐式

隐式许可是为是使用如JavaScript这样的脚本语言实现在浏览器中的客户端进行优化的简化的授权码流程。在隐式流程中,不会给客户端分发授权码,客户端会被直接分发访问令牌(作为资源所有者授权的结果)。许可类型是implicit,因为不会分发(如授权码这样的)中间凭证(然后用其去获取访问令牌)。

当在隐式许可流程中分发一个访问令牌时,授权服务器不会对客户端进行认证。在一些情况下,客户端的身份可以通过用来传递访问令牌回客户端的重定向URI来验证。访问令牌可能会暴露给资源所有者或者其他可以访问资源所有者的用户代理的应用。

隐式许可提升了一些客户端的响应和效率(比如一个实现为浏览器内应用的客户端),因为它减少了获取访问令牌所需的请求来回次数。但是应该权衡下这便利性与使用隐式许可导致的安全隐患,比如那些在章节10.3和10.16中描述的,特别是在你能够使用授权码许可的时候。

1.3.3 资源所有者密码凭证

资源所有者密码凭证(例如,有户名和密码)可以直接被用作授权许可来获取访问凭证。只有当资源所有者高度信任这客户端(比如,客户端是设备操作系统或者一个高权限应用的一部分),并且其他授权许可类型(比如授权码)用不上的时候,才可以使用这个凭证。

尽管这个许可类型需要客户端直接获取资源所有者的凭证,资源所有者的凭证只用于单个请求并用于交换访问令牌。这个许可类型下,通过使用凭证交换一个长期的访问令牌或刷新令牌,客户端不会需要存储资源所有者的凭证以在之后使用。

1.3.4 客户端凭证

当授权范围限制在客户端控制下的受保护资源,或者限制在先前由授权服务器布置的受保护资源时,客户端凭证(或者其他形式的客户端授权)可以用做授权许可。典型地,当客户端是代表他自己来执行(客户端也是资源所有人)或者是在请求访问基于之前由授权服务器分配的授权的受保护资源时,客户端凭证用做授权许可。

1.4 访问令牌

访问令牌适用于访问受保护资源的凭证。一个访问令牌是一个代表着分发给客户端的授权的字符串。这个字符串对于客户端通常是含糊的,令牌代表着访问的特定范围和时长,由资源所有者许可,并且由资源服务器和授权服务器强制使用。

这个令牌可能采用一个用于获取授权信息的标识符,或者也可以以可验证的方式自包含授权信息(即,包含一些数据和一个签名的令牌字符串)。为了让客户端使用令牌,可能需要额外的身份验证凭据,这不在本规范的讨论范围。

访问令牌提供了一个抽象层,使用单个资源服务器认得的令牌替代了不同的授权结构(即,用户名和密码)。这种抽象使得分发访问令牌比用于获取它们的授权许可更具限制性,并且消除了资源服务器理解各种身份验证方法的需要。

基于资源服务器的安全要求,访问令牌可以有不同的格式、结构和使用方法(例如,加密属性)。访问令牌属性和用来访问受保护的资源的方法不在这篇规范的讨论范围,它由如[RFC6750]这样的兄弟规范定义。

1.5 刷新令牌

刷新令牌是用于获取访问令牌的凭证。刷新令牌由授权服务器分发给客户端用于在当前访问令牌失效或者过期时获取新的访问令牌,或者用来获取拥有一致或更窄访问范围的额外访问令牌(访问令牌可能有更短的生命周期,以及比资源所有者授权的少的许可)刷新令牌的分发是可选的,授权服务器谨慎决定是否分发。如果授权服务器分发了一个刷新令牌,它会随同访问令牌一起被下发(即图1中的步骤D)。

一个刷新令牌是一个字符串,代表着资源所有者给客户端的授权许可。这个字符串通常对于客户端是含糊的。这令牌使用一个用于提取授权信息的标识符。和访问令牌不一样,刷新令牌仅用于和授权服务器交互使用,从不会发给资源服务器。

图 2: 刷新一个过期的访问令牌

图2中阐述的流程包含以下步骤:

A. 客户端通过与授权服务器进行认证并提供一个授权许可来请求一个访问令牌。
B. 授权服务器对客户端进行认证并验证授权许可,如果有效,则分发一个访问令牌和一个刷新令牌
C. 客户端通过提供访问令牌,向资源服务器请求受保护的资源。
D. 资源服务器验证访问令牌,如果有效,则服务这个请求
E. 步骤C和D重复知道访问令牌过期。如果客户端知道了访问令牌过期,它会跳到步骤G;否则,它会发起另一个受保护的资源请求。
F. 由于访问令牌是无效的,资源服务器会返回一个 无效令牌错误
G. 客户端通过与授权服务器进行认证并提供刷新令牌来请求一个新的访问令牌。客户端认证需求是基于客户端类型和授权服务器的政策的。
H. 授权服务器对客户端进行认证并验证刷新令牌,如果有效,则分发一个新的访问令牌(以及可选的一个新的刷新令牌)。

步骤 C、D、E和F超出了这篇规范的讨论范围,描述在章节7中。

1.6 TLS 版本

不管何时这篇规范用到的传输层加密(Transport Layer Security, TLS)的推荐版本都应该基于部署广度和安全性随着时间不断变化。在写作的时刻,TLS版本1.2[RFC5246]是最新的版本,但是部署的不够广泛,并且可能相关实现也不够多。TLS 版本1.0[RFC2246]是最广泛部署的版本,并将提供最广泛的互用性。

具体实现也许也会支持额外的传输层加密机制以满足他们的加密需求。

1.7 HTTP重定向

这篇规范广泛使用HTTP重定向,客户端或者授权服务器使用其指引资源所有者的用户代理跳转到另一个目标。尽管这篇规范中使用的是HTTP 302状态码,但其他能够让用户代理完成这个重定向的方法都是可以使用的,并且会被认为是一个实现细节。

1.8 互用性

OAuth 2.0 提供了一个具有明确定义的安全属性的丰富的授权框架。然而,作为一个有丰富的,自身带有许多可选组件具有高度扩展性的框架,这个规范很可能产生广泛的不可互用实现。

另外,这个规范中有一些要求的组件是部分或完全未定义的(例如,客户端注册、授权服务器的能力,端点发现)。如果没有这些组件的话,客户端就必须要人工配置指定授权服务器和资源服务器才有办法交互。

这个框架设计时有个明确的预期就是未来的工作将定义实现全网互用性所必需的规范性配置文件和扩展。

1.9 符号约定

这篇规范中的关键词 “必须(MUST)”、“绝不(MUST NOT)”、“要求(REQUIRED)”、“应当(SHALL)”、“不应当(SHALL NOT)”、“SHOULD(应该)”、“SHOULD NOT(不应该)”、“推荐(RECOMMENDED)”、"可能(MAY)"和“可选的(OPTIONAL)”被解释于[RFC2119]。

这篇规范使用[RFC5234]中的ABNF标记(Augmented Backus-Naur Form)。另外,规则 URI-reference 包含在“统一资源标识符 (URI):通用语法”中 [RFC3986]。

安全相关的特定术语应该要按照[RFC4949]中定义的来理解。这些术语包括但不限于,“攻击(attack)”、“身份验证(authentication)”、“授权(authorization)”、“凭据(certificate)”、“机密性(confidentiality)”、“身份凭证(credential)”、“加密(encryption)”、“身份识别(identity)”、“签名(sign)”、“签名(signature)”、“信任(trust)”、“验证(validate)”和“证实(verify)”。

除非特别说明,否则所有的协议参数名和参数值都是大小写敏感的。

2 客户端注册

在发起协议前,客户端要在授权服务器上注册。客户端在授权服务器上注册的方法不在这篇规范的讨论访问,但是典型地是通过终端用户直接与HTML表单交互实现的。

客户端注册客户端注册不需要客户端和授权服务器直接的交互。当授权服务器支持后,可以依靠其他方式来建立信任并获取要求的客户端属性(例如,重定向URI,客户端类型)。比如,可以使用一个自提交或第三方提交的断言来完成注册,或者也可以通过让授权服务器使用受信任通道进行服务发现。

当注册一个客户端时,客户端开发者应当:

  • 如章节2.1里头一样指定客户端类型
  • 如章节3.1.2里头描述的,提供它的客户端重定向URI
  • 包含进其他授权服务器要求的信息(例如,应用名、网址、描述、logo图标,接受法律条款)

2.1 客户端类型

OAuth定义了两种客户端类型,基于它们与授权服务器进行安全身份验证的能力(即,保持客户端自身凭据机密性的能力):

机密(confidential)

  • 能够维持它们自身凭证的机密性(例如,实现在一个加密服务器上,有限制地访问它们的凭据),或者能够用其他方法加密客户端身份凭证的客户端

公开(public)

  • 不能够维持它们自身凭证的机密性(例如,执行在由资源所有者使用的设备上的客户端,例如需要安装的本地应用程序,或者基于web浏览器的应用程序),并且不能使用其他方法加密客户端身份凭证的客户端

客户端类型如何确定是基于授权服务器对安全验证的定义以及它可接受的客户端凭证暴露等级。授权服务器不应该对客户端类型进行假定。

一个客户端可能会实现为一个分布式组件集,每个组件有不同的客户端类型和安全上下文(例如,一个拥有受信任的基于服务器的组件与公共的基于浏览器的组件的分布式的客户端)。如果授权服务器不为此类客户端提供支持或不提供有关其注册的指导,则客户端应将每个组件注册为单独的客户端。

这篇规范是按照以下类型客户端来设计的:

web应用

  • Web 应用程序是在 Web 服务器上运行的机密客户端。资源所有者通过运行在他使用的设备上的用户代理渲染出的HTML用户接口来访问客户端。客户端凭证以及任何分发给客户端的访问令牌都存储在web服务器上,没有暴露给资源所有者,资源所有者也访问不到。

基于用户代理的应用

  • 基于用户代理的应用程序是公开客户端,客户端代码会从web服务器下载到资源所有者使用的设备上的用户代理(例如,web浏览器)中,并在其上执行。资源所有者可以轻易访问(通常是直接可见)到协议数据和凭证。由于这种应用程序驻留在用户代理中,在请求授权的时候,它们可以无缝使用用户代理的能力。

本地应用

  • 本地应用是公开客户端,它被安装和运行在资源所有者使用的设备上。资源所有者可以访问到协议数据和凭证。我们默认这种应用中存的客户端授权凭证都是可以提取的。另一方面,动态分发的凭证,如访问令牌和刷新令牌可以获得可接受级别的保护。至少,这些凭据被保护不受可能与应用程序交互的恶意服务器的影响。在某些平台上,可能能保护这些凭据免受驻留在同一设备上的其他应用程序的影响。

2.2 客户端标识码

授权服务器会给注册的客户端分发一个客户端标识码(client identifier) – 一个代表着由客户端提供的注册信息的唯一字符串。客户端识别码不用保密;它被暴露给资源所有者,并且绝不独立用于客户端身份识别。客户端标识符对于授权服务器是唯一的。

这篇文档没有规定客户端标识码字符串的大小。客户端不应该做关于标识码大小的假设。授权服务器应该在文档中写下它分发的标识码的可能大小。

2.3 客户端身份验证

如果客户端类型是机密,客户端和授权服务器建立满足授权服务器安全要求的客户端认证方法。授权服务器可能接受满足它安全要求的任何形式的客户端身份验证。

机密客户端典型地会提交(或建立)一个集合的客户端凭证(例如,密码、公私钥对),用于与授权服务器做身份验证。

授权服务器可能与公开客户端建立一个客户端身份认证方法。但是,授权服务器绝不能依赖公开服务器身份认证用做识别客户端的用途。

客户端绝不能在每个请求中使用超过一种身份认证方法。

2.3.1 客户端密码

拥有客户端密码的客户端们可能使用[RFC2617]中定义的HTTP基础身份验证方案来与授权服务器进行身份验证。客户端标识符使用附件B中的“application/x-www-form-urlencoded”编码算法来编码,编码的值被用做用户名;客户端密码使用同样的算法来编码,并被用做密码。为了能够验证提交客户端密码来身份验证的客户端,授权服务器必须支持HTTP基础身份验证方案。

比如:

Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

可选的,授权服务器可能支持在请求体内使用以下参数来包含客户端凭据:

client_id

  • 要求。 在章节2.2描述的注册过程中,分发给客户端的客户端标识符

client_secret

  • 要求。 客户端密钥。 如果客户端密钥是一个空字符串的话,客户端可能省略这个参数。

在请求体内使用两个参数来包含客户端凭证的这个方试不被推荐,应该限制用于无法直接使用HTTP基础身份验证方案(或者其他基于密码的HTTP身份验证方案)的客户端。参数仅可在请求体内传输,一定不能包含在请求URI中。

比如,一个使用包体参数来刷新访问令牌(章节6)的请求(额外的换行符仅用于演示目的):

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA&client_id=s6BhdRkqt3&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

授权服务器必须要求在使用密码身份验证发送请求时使用如章节1.6中描述的TLS。

由于这个客户端身份验证方法牵涉到了密码,授权服务器必须保护使用它的任何端点免于暴力破解。

2.3.2 其他身份验证方法

授权服务器可能支持任何合适的匹配它安全要求的HTTP身份验证方案。当使用其他身份验证方法时,授权服务器必须定义客户端标识码(注册记录)与身份验证方案间的映射。

2.4 未注册的客户端

这篇规范没有禁止使用未注册的客户端。但是,使用这类客户端不在此规范讨论的范围内,需要进行更多的安全分析,审查与其互用性的影响。

3 协议端点

授权过程利用了两个授权服务器端点(HTTP资源):

  • 授权端点 - 被客户端用于从资源所有者通过用户代理重定向来获得授权
  • 令牌端点 - 被客户端用于交换授权许可,即访问令牌,典型地要进行客户端身份验证。

以及一个客户端端点:

  • 重定向端点 - 由授权服务器用于通过资源所有者的用户代理返回包含授权凭证的答复给客户端。

不是每个授权许可类型都用到了所有端点。扩展许可类型可能会按需定义额外的端点。

3.1 授权端点

授权端点被用于和资源所有者交互,并获得授权许可。授权服务器必须首先验证资源所有者的身份。授权服务器对资源所有者进行身份验证的方式(例如,用户名与密码登录、会话cookies)超出了这篇规范的讨论范围。

端点URI可能包含一个“application/x-www-form-urlencoded”格式(见附件B)请求组件([RFC3986] 章节3.4),当添加其他query参数的时候,原先的必须保留。端点URI绝不能包含fragment组件。

由于对授权端点的请求会导致用户身份验证和(在HTTP答复中)明文凭证的传输,授权服务器必须要求在发送请求到授权端点时使用章节1.6中描述的TLS。

授权服务器必须支持使用HTTP “GET”方法[RFC2616]来访问授权端点,也可能支持使用“POST”方法。

发送的没有值的参数必须被视为从请求中省略。授权服务器必须忽略无法识别的请求参数。请求和响应参数不得被包含超过一次。

3.1.1 答复类型

授权端点被授权码许可类型和隐式许可类型流程使用。客户端通过使用以下参数告知授权服务器它想要的许可类型。

response_type

  • 要求。 这个值必须是如章节4.1.1中请求授权码时填的“code”,章节4.2.1中请求访问令牌(隐式许可)时填的“token”,或者章节8.4中描述的注册的扩展值之一。

扩展答复类型可能包含一个空格(%x20)分割的列表,列表中值的顺序并不重要(例如,答复类型"a b"和"b a"是一样的)。这种复合答复类型的含义由它们各自的规范定义。

如果一个授权请求没有"response_type"参数,或者不认得参数值,授权服务器必须返回如章节4.1.2.1中描述的一个错误答复。

3.1.2 重定向端点

授权服务器在完成它与资源所有者的交互后,将资源所有者的用户代理重定向回客户端。授权服务器将用户代理重定向回客户端的重定向端点,重定向端点在之前已经在客户端注册过程中或者通过授权请求与授权服务器进行了认证。

重定向端点URI必须是如[RFC3986]章节4.3中定义的绝对路径URI。端点URI可能包含一个“application/x-www-form-urlencoded”格式(见附件B)请求组件([RFC3986] 章节3.4),当添加其他请求参数的时候,这请求组件必须保留。端点URI绝不能包含fragment组件。

3.1.2.1 端点请求机密性

当请求的答复类型是“code”或者“token”,或者当重定向请求会导致敏感凭证在开放网络上传输,重定向端点应该要求使用如章节1.6中描述的TLS。这篇规范没有强制使用TLS是因为在写作时,要求客户端部署TLS对于许多客户端开发者是个很大的障碍。如果没法使用TLS,授权服务器应该在重定向前警告资源所有者这是个不安全端点(例如,在授权请求中展示一条消息)。

缺失传输层加密可能对客户端的安全性以及它被授权访问的受保护资源有严重影响。当授权过程被客户端用作一种委托的终端用户身份验证形式(例如,第三方登录服务)时,传输层安全性的使用尤其重要。

3.1.2.2 注册要求

授权服务器必须要求以下客户端注册它们的重定向端点。

  • 公开客户端
  • 使用隐式许可类型的机密客户端

授权服务器应该要求所有客户端都在用到授权端点前注册它们的重定向端点。

授权服务器应该要求客户端提供完整的重定向URI(客户端可能使用“state”请求参数实现每个请求的定制性)。如果不可能要求完整重定向URI的注册,授权服务器应该要求注册URI scheme、来源和路径(仅允许客户端在请求授权时动态地变更重定向URI的query组件)。

授权服务器可能允许客户端注册多个重定向端点。

如果不强制要求注册重定向URI的话,授权服务器会被攻击者用做一个开放的重定向器,如章节10.15中描述的。

3.1.2.3 动态配置

如果已经注册了多个重定向URI,如果只注册了部分重定向URI,或者如果没有注册任何重定向URI,客户端必须在授权请求中使用“redirect_uri”请求参数包含进一个重定向URI。

当授权请求中包含了一个重定向URI,授权服务器必须将其值与已经注册的URI(或者URI组件)进行比较并匹配上其中一个,如[RFC3986]章节6中所描述的。如果客户端的注册包含了完整的重定向URI,授权服务器必须将两个URI使用简单字符串比较进行比较,如[RFC3986]章节6.2.1中定义的。

3.1.2.4 无效端点

如果授权请求由于缺失、无效或者不匹配重定向URI而失败了,授权服务器应该通知资源所有者发生了错误,并且绝不能自动重定向用户代理到无效的重定向URI。

3.1.2.5 端点内容

到客户端端点的重定向请求典型地会产生一个HTML文档答复,由用户代理来处理。如果这HTML答复直接作为重定向请求的结果提供,则 HTML 文档中包含的任何脚本都将在能完全访问重定向 URI 及其包含的凭据的情况下执行。

客户端不应该在重定向端点答复中包含任何第三方脚本(例如,第三方分析、社交插件、广告网络)。它应该从URI中提取凭证并再次跳转用户代理到另一个不会(在URI或者其他地方)暴露凭证的端点。如果包含了第三方脚本,客户端必须确保它自己的(用于从URI中提取并移走凭证的)脚本将先执行。

3.2 令牌端点

令牌端点被客户端端点用于通过提供它的授权许可或者刷新令牌来获取访问令牌。令牌端点被与除了隐式许可类型之外(由于直接分发了访问令牌)的每个授权许可一起使用。

客户端用来获取令牌端点的方法不在这篇规范的讨论范围,但是位置典型地会写在服务文档中。

端点URI可能会包含一个"application/x-www-form-urlencoded"格式(见附件B)的query组件([RFC3986]章节3.4),当添加其他query参数的时候,原来的必须保留。端点URI绝不能包含fragment组件。

由于对授权端点的请求会导致(在HTTP请求和答复中)明文凭证的传输,授权服务器必须要求在发送请求到令牌端点时使用章节1.6中描述的TLS。

授权服务器必须支持使用HTTP “POST”方法来做访问令牌请求。

发送的没有值的参数必须被视为从请求中省略。授权服务器必须忽略无法识别的请求参数。请求和响应参数不得被包含超过一次。

3.2.1 客户端身份验证

机密客户端或者其他被分发了客户端凭证的客户端在对令牌端点发起请求时必须如章节2.3所述与授权服务器进行身份验证。客户端身份验证用于:

  • 强制绑定刷新令牌和授权码到被分发的客户端。当授权码是在不安全的通道上传递给重定向端点或者当重定向URI还没被完整形式注册时,客户端身份验证是至关重要的。
  • 通过禁用客户端或更改其凭据使受感染的客户端中恢复,从而防止攻击者滥用被盗的刷新令牌。更改一组客户端凭据比撤销一整组刷新令牌要快得多。
  • 实现身份验证管理的最佳实践,要求周期性地凭证轮换。轮换一整组刷新令牌可能很有挑战,而轮换一组客户端凭证就简单的多了。

一个客户端可能使用“client_id”请求参数以在发送请求给令牌端点时识别它自己。在发往令牌端点的“授权码”“许可类型”请求中,未身份验证的客户端必须发送它的“client_id”以避免它自己不小心收到了给另一个“client_id”分发的授权码。这保护客户端免于授权码替代。(这对于受保护的资源没有提供额外的安全性)

3.3 访问令牌Scope

授权端点和令牌端点使得客户端能够通过使用“scope”请求参数说明访问请求的权限范围。在答复中,授权服务器使用“scope”答复参数来告知客户端 分发的访问令牌的scope。

scope参数的值表达为空格分割的大小写敏感的列表。字符串是由授权服务器定义的。如果值中包含多个空格分割的字符串,它们的顺序是无所谓的,每个字符串都会往请求scope增加额外的访问范围。

     scope       = scope-token *( SP scope-token )
     scope-token = 1*( %x21 / %x23-5B / %x5D-7E )

授权服务器可能基于授权服务器的政策或者资源所有者的指示,完全或部分地忽略客户端请求的scope。如果分发的访问令牌scope与客户端请求的不同,授权服务器必须包含“scope”答复参数来告知客户端实际许可的scope。

如果客户端在请求授权时忽略了scope参数,授权服务器必须要不使用预定义默认值处理请求,要不因为无效的scope让请求失败。授权服务器应该文档化它的scope要求以及(如果定义的)默认值。

4 获得授权

为了请求一个访问令牌,客户端要要从资源所有者处获取授权。授权是通过授权许可的形式表达的,客户端用其来请求访问令牌。OAuth定义了四种许可类型:授权码、隐式、资源所有者密码凭证和客户端凭证。它也提供扩展机制以定义额外的许可类型。

4.1 授权码许可

授权码许可类型被用于获取访问令牌与刷新令牌,为机密客户端做了优化。由于这是一个基于重定向的流程,客户端必须能够与资源所有者的用户代理(典型地是一个web浏览器)进行交互,并能够接收(通过重定向)从授权服务器进来的请求。

图 3:授权码流程
注意: 阐述步骤(A)、(B)和©的线在穿过用户代理时被分成了两部分。

图3中阐述的流程包含以下步骤:
(A) 客户端通过引导资源所有者的用户代理到授权端点以发起流程。客户端的请求会包含它的客户端标识码、请求的scope、本地state和一个重定向URI,授权服务器会在访问被许可(或者否决)时把用户代理跳转回这URI。

(B) 授权服务器(通过用户代理)对资源所有者进行身份验证,并确定资源所有者是许可还是否决了客户端的访问请求。

© 假设资源所有者许可了访问,授权服务器会使用之前提供的重定向URI(在请求中带的,或者是客户端注册中填的)重定向用户代理回客户端。重定向URI包含一个授权码以及客户端之前提供的任意本地state。

(D) 客户端通过给出在前一个步骤中获得的授权码,从授权服务器的令牌端点请求一个访问令牌。当发起请求时,客户端会在授权服务器进行身份认证。客户端会带上用于获取授权码的重定向URI以用于验证。

(E) 授权服务器对客户端进行身份认证,验证授权码,并确认收到的重定向URI与步骤C中用于重定向到客户端的URI一致。如果有效,授权服务器就会答复一个访问令牌,以及可选的,一个刷新令牌。

4.1.1 授权请求

客户端通过使用“application/x-www-form-urlencoded”格式添加以下参数到授权端点URI的query组件中来构建请求URI。

response_type
	要求。 值必须被设为“code”。
client_id
	要求。 如章节 2.2中所描述的客户端标识码。
redirect_uri
	要求。 如章节 3.1.2中描述的。
scope
	可选。 如章节 3.3中描述的访问请求scope。
state
	推荐。 一个含糊的值,被客户端用于维护请求与回调间的状态。授权服务器会在重定向用户代理回客户端时包含这个值。这个参数应该被用于避免受到跨站请求伪造(CSRF, Cross-site request forgery)攻击,如章节10.12描述的。

客户端通过使用HTTP重定向答复,或者其他可用的方法,经由用户代理引导资源所有者到构筑的URI上。

比如,客户端引导用户代理使用TLS发起以下HTTP请求(额外的换行符仅用于展示目的):

    GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

授权服务器验证请求以确保所有要求的参数都已给出并且有效。如果请求是有效的,授权服务器对资源所有者进行身份认证并获取授权决定(通过询问资源所有者或者其他方法确认许可)。

当确认决定,授权服务器会使用HTTP重定向答复引导用户代理到提供的客户端重定向URI,或者通过其他方法由用户代理完成这事。

4.1.2 授权答复

如果资源所有者许可了访问请求,授权服务器分发一个授权码并通过使用“application/x-www-form-urlencoded”格式添加以下参数到重定向URI的query组件中来将其传递给客户端,见附件B:

code
	要求。 由授权服务器生成的授权码。授权码必须在分发后短时间内过期以减低泄漏的风险。推荐的最大授权码生命周期是10分钟。客户端绝不能使用授权码超过一次。如果授权码被使用超过一次,授权服务器必须拒绝请求并(如果可能时)撤销所有之前基于这个授权码分发的令牌。授权码与客户端标识码和重定向URI是捆绑的。

state
	如果客户端授权请求给出了“state”参数,就是要求的。与从客户端收到的一模一样的值。

比如,授权服务器通过发送以下HTTP答复重定向用户代理:

     HTTP/1.1 302 Found
     Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

客户端必须忽略不认识的答复参数。这篇规范没有规定授权码字符串的长度。客户端应该避免假定授权码值大小。授权服务器应该文档化它分发的任意值的大小。

4.1.2.1 错误答复

如果请求由于缺失、无效或者不匹配重定向URI、或者由于客户端标识码缺失或无效而失败,授权服务器应该告知资源所有者这个错误,并且绝不能自动地重定向用户代理到无效的重定向URI。

如果资源所有者拒绝了访问请求,或者如果访问请求由于除了缺失或无效重定URI外的原因失败了,授权服务器通过使用“application/x-www-form-urlencoded”格式添加以下参数到重定向URI的query组件中来告知客户端。

error
	要求。 以下之一的单个ASCII[USASCII]错误码:
	invalid_request
		请求缺少要求的参数,可能是无效的参数值、有个参数给出超过一次或者其他错误。
	unauthorized_client
		客户端不被授权使用这此方法请求授权码。
	access_denied
		资源所有者或者授权服务器否决了请求。
	unsupported_response_type
		授权服务器不支持使用这个方法获取授权码。
	invalid_scope
		请求的scope是无效、未知或者格式错误的。
	server_error
		授权服务器遇到了异常情况而无法服务请求(需要这个错误码,因为500服务器内部错误HTTP状态码无法通过HTTP重定向返回给客户端)。
	temporarily_unavailable
		授权服务器目前由于临时的过载或者维护而无法处理请求。(需要这个错误码,因为503服务不可用HTTP状态吗无法通过HTTP重定向返回给客户端)
	“error”参数的值绝不能包含超出字符集 %x20-21 / %x23-5B / %x5D-7E 的字符。
error_description
	可选。 人类可读的ASCII[USASCII]文本,提供额外的信息,用于协助客户端开发者理解发生的错误。
error_uri
	可选。 一个定义了人类可读网页的URI,上面是关于错误的信息,用于提供客户端开发者关于错误的额外信息。“error_uri”参数的值必须遵从URI参考语法,并且绝不能包含超出字符集 %x21 / %x23-5B / %x5D-7E 的字符。
state
	如果客户端授权请求给出了“state”参数,就是要求的。与从客户端收到的一模一样的值。
举个例子,授权服务器通过发送以下HTTP答复码重定向用户代理:
   HTTP/1.1 302 Found
   Location: https://client.example.com/cb?error=access_denied&state=xyz

4.1.3 访问令牌请求

客户端通过在HTTP请求体内使用“application/x-www-form-urlencoded”格式并使用UTF-8编码发送以下参数来请求令牌端点:

grant_type
	要求。 值必须被设为“authorization_code”。
code
	要求。 从授权服务器收到的授权码。
redirect_uri
	要求, 如果“redirect_uri”参数如章节4.1.1所述包含在授权请求中,它们的值必须一致。
client_id
	要求, 如果客户端没有如章节3.2.1所述与授权服务器进行身份验证。

如果客户端类型是机密,或者客户端被分发了客户端凭证(或者有其他身份认证需求),客户端必须如章节3.2.1所述与授权服务器进行身份验证。

例如,客户端使用TLS发起如下HTTP请求(额外的空行仅用于展示):

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

授权服务器必须:

  • 对于客户端类型是机密,或者对于客户端被分发了客户端凭证(或者有其他身份认证需求)的,要求客户端身份验证。
  • 如果包含了客户端身份认证,进行身份认证
  • 确保授权码被分发给了身份认证过的机密客户端,或者如果客户端是公开类型的,确保授权码是分发给了请求中的“client_id”。
  • 验证授权码有效,并且
  • 确保如果如章节4.1.1所述在发起授权请求中包含了“redirect_uri”参数,则这个请求中也给出了“redirect_uri”参数,并且确保它们的值是一致的。

4.1.4 访问令牌答复

如果访问令牌请求是有效且被授权的,授权服务器如章节5.1所述分发一个访问令牌以及可选的刷新令牌。如果客户端身份认证失败或者无效,授权服务器如章节5.2所述返回一个error答复。

一个示例的成功答复:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

4.2 隐式许可

隐式许可被用于获取访问令牌(它不支持发布刷新令牌)并为操作特定重定向URI的公开客户端做了优化。这些客户端典型地使用如JavaScript的脚本语言实现在浏览器中。

由于这是个基于重定向的流程,客户端必须能够与资源所有者的用户代理(典型的是一个web浏览器)交互,并能够(经由重定向)接受来自授权服务器进入的请求。

不像授权码许可类型那样对授权和访问令牌分别进行请求,在这种许可类型中,客户端在授权请求的结果中接收访问令牌。

隐式许可类型不包含客户端身份认证,依赖于资源所有者的在场以及重定向URI的注册。由于访问令牌被编码进重定向URI,它可能会暴露给资源所有者以及安装在同个设备上的其他应用。


图 4:隐式许可流程
注意: 阐述步骤(A)和(B)的线在穿过用户代理时被分成了两部分。

图4中阐述的流程包含以下步骤:

(A) 客户端通过引导资源所有者的用户代理到授权端点上而发起流程。客户端的请求会包含它的客户端标识码、请求的scope、本地state和一个重定向URI,授权服务器会在访问被许可(或者否决)时把用户代理跳转回这URI。

(B) 授权服务器(通过用户代理)对资源所有者进行身份验证,并确定资源所有者是许可还是否决了客户端的访问请求。

© 假设资源所有者许可了访问,授权服务器会使用之前提供的重定向URI重定向用户代理回客户端。重定向URI还会在URI fragment中包含访问令牌。

(D) 用户代理执行重定向指令,请求web主机的客户端资源(这时不会包含fragment部分[RFC2616])。用户代理会在本地保留fragment信息。

(E) web主机的客户端资源返回了一个web网页(典型地是一个代理嵌入式脚本的HTML文档),这网页能够访问包括保留在用户代理上的fragment的全部重定向URI,并提取包含在fragment中的访问令牌(和其他参数)。

(F) 用户代理本地运行由web主机的客户端资源提供的脚本,这脚本会提取访问令牌。

(G) 用户代理将访问令牌传递给客户端。

见章节1.3.2和9了解使用隐式许可的背景。见章节10.3和10.16了解使用隐式许可的重要安全考虑。

4.2.1 授权请求

客户端通过使用“application/x-www-form-urlencoded”格式添加以下参数到授权端点URI的query组件中来构建请求URI。

response_type
	要求。 值必须被设置为“token”。
client_id
	要求。 如章节2.2描述的客户端标识码。
redirect_uri
	可选。 如章节3.1.2描述的。
scope
	可选。 如章节3.3描述的访问请求的scope。
state
	推荐。 一个含糊的值,被客户端用于维护请求与回调间的状态。授权服务器会在重定向用户代理回客户端时包含这个值。这个参数应该被用于避免受到跨站请求伪造(CSRF, Cross-site request forgery)攻击,如章节10.12描述的。

客户端通过使用HTTP重定向答复,或者其他可用的方法,经由用户代理引导资源所有者到构筑的URI上。

比如,客户端引导用户代理使用TLS发起以下HTTP请求(额外的换行符仅用于展示目的):

    GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
    Host: server.example.com

授权服务器验证请求以确保所有要求的参数都已给出并且有效。授权服务器必须验证它将重定向访问令牌的重定向URI与如章节3.1.2中描述的由客户端注册的重定向URI匹配。

如果请求是有效的,授权服务器对资源所有者进行身份认证并获取授权决定(通过询问资源所有者或者其他方法确认许可)。

当确认决定,授权服务器会使用HTTP重定向答复引导用户代理到提供的客户端重定向URI,或者通过其他方法由用户代理完成这事。

4.2.2 访问令牌答复

如果资源所有者许可了访问请求,授权服务器分发一个授权码并通过使用“application/x-www-form-urlencoded”格式添加以下参数到重定向URI的fragment组件中来将其传递给客户端,见附件B:

access_token
	要求。 由授权服务器分发的访问令牌。
token_type
	要求。 如章节7.1中描述的,分发的令牌类型。 值是忽略大小写的。
expires_in
	推荐。 以秒为单位的访问令牌生命周期。比如,值“3600”表明访问令牌将从生成答复起的一小时后过期。如果省略了,授权服务器应该由其他方法提供过期时间,或者文档化默认值。
scope
	如过和客户端请求的一致则是可选;否则,要求。如章节 3.3中描述的访问请求scope。
state
	要求,如果“state”参数在客户端授权请求中给出。与从客户端处收到的一致的值。

授权服务器绝不能分发刷新令牌。

比如,授权服务器通过发送以下HTTP答复重定向用户代理(额外的空行仅用于展示目的):

     HTTP/1.1 302 Found
     Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600

开发者应该注意,一些用户代理不支持在HTTP “Location” 答复头字段中包含fragment组件。这样的客户端需要使用其他方法来重定向客户端,而不是使用3xx重定向答复 – 比如,返回一个包含‘继续’按钮的HTML页面,点击按钮后链接到重定向URI。

客户端必须忽略不认识的答复参数。这篇规范没有规定授权码字符串的长度。客户端应该避免假定授权码值大小。授权服务器应该文档化它分发的任意值的大小。

4.2.2.1 错误答复

如果请求由于缺失、无效或者不匹配重定向URI、或者由于客户端标识码缺失或无效而失败,授权服务器应该告知资源所有者这个错误,并且绝不能自动地重定向用户代理到无效的重定向URI。

如果资源所有者拒绝了访问请求,或者如果访问请求由于除了缺失或无效重定URI外的原因失败了,授权服务器通过使用“application/x-www-form-urlencoded”格式添加以下参数到重定向URI的fragment组件中来告知客户端。

error
	要求。 以下之一的单个ASCII[USASCII]错误码:
	invalid_request
		请求缺少要求的参数,可能是无效的参数值、有个参数给出超过一次或者其他错误。
	unauthorized_client
		客户端不被授权使用这此方法请求访问令牌。
	access_denied
		资源所有者或者授权服务器否决了请求。
	unsupported_response_type
		授权服务器不支持使用这个方法获取授权码。
	invalid_scope
		请求的scope是无效、未知或者格式错误的。
	server_error
		授权服务器遇到了异常情况而无法服务请求(需要这个错误码,因为500服务器内部错误HTTP状态码无法通过HTTP重定向返回给客户端)。
	temporarily_unavailable
		授权服务器目前由于临时的过载或者维护而无法处理请求。(需要这个错误码,因为503服务不可用HTTP状态吗无法通过HTTP重定向返回给客户端)
	“error”参数的值绝不能包含超出字符集 %x20-21 / %x23-5B / %x5D-7E 的字符。
error_description
	可选。 人类可读的ASCII[USASCII]文本,提供额外的信息,用于协助客户端开发者理解发生的错误。
	“error_description”参数值绝不能包含超出字符集 %x20-21 / %x23-5B / %x5D-7E 的字符。
error_uri
	可选。 一个定义了人类可读网页的URI,上面是关于错误的信息,用于提供客户端开发者关于错误的额外信息。“error_uri”参数的值必须遵从URI参考语法,并且绝不能包含超出字符集 %x21 / %x23-5B / %x5D-7E 的字符。
state
	如果客户端授权请求给出了“state”参数,就是要求的。与从客户端收到的一模一样的值。

举个例子,授权服务器通过发送以下HTTP答复码重定向用户代理:

   HTTP/1.1 302 Found
   Location: https://client.example.com/cb#error=access_denied&state=xyz

4.3 资源所有者密码凭证许可

资源所有者密码凭证许可类型很适合于当资源所有者高度信任这客户端,比如,客户端是设备操作系统或者一个高权限的应用。授权服务器应该特别小心地开启这个许可类型并且仅在其他流程用不上的时候,才可以使用这个凭证。

这个许可类型很适合于可以获取资源所有者的凭证(用户名和密码,典型地使用交互表单)的客户端。它还用于通过将存储的凭据转换为访问令牌,将使用直接身份验证方案(如HTTP Basic或摘要身份验证)的现有客户端迁移到OAuth。


图5:资源所有者密码凭证流程

图5中阐述的流程包含如下步骤:

(A) 资源所有者给客户端提供它的用户名和密码

(B) 客户端通过带上从资源所有者处收到的凭证,从授权服务器的令牌端点请求一个访问令牌。当发起请求时,客户端与授权服务器进行身份验证。

© 授权服务器对客户端进行身份认证,并验证资源所有者的凭证,如果有效,分发一个访问令牌。

4.3.1 授权请求和答复

客户端用来获取资源所有者凭证的方法超出了这篇规范的讨论范围。客户端一获取访问令牌就必须抛弃凭证。

4.3.2 访问令牌请求

客户端通过使用“application/x-www-form-urlencoded”格式添加以下参数并使用UTF-8编码来构建请求体以发起对令牌端点的请求。

grant_type
	要求。 值必须被设置为“password”。
username
	要求。 资源所有者的用户名。
password
	要求。 资源所有者的密码。
scope
	可选。 如章节3.3描述的访问请求的scope。

如果客户端类型是机密,或如果客户端被分发了客户端凭证(或者要求其他身份验证),客户端必须如章节3.2.1所述在授权服务器上进行身份验证。

例如,客户端使用传输层加密发起如下HTTP请求(额外的空行仅用于展示目的):

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=password&username=johndoe&password=A3ddj3w

授权服务器必须:

  • 对于机密客户端或者被分发了客户端凭证(或者有其他身份验证要求)的任何客户端要求进行客户端身份验证。
  • 如果包含了客户端身份验证,进行验证,并且
  • 验证使用现有的密码验证算法验证资源所有者的密码凭证。

由于这个访问令牌请求用到了资源所有者的密码,授权服务器必须保护端点免于暴力破解攻击(例如,用上限速或者生成报警)。

4.3.3 访问令牌答复

如果访问令牌请求有效并且得到授权,授权服务器会如章节5.1所述分发一个访问令牌和可选的刷新令牌。如果客户端身份认证失败或者请求无效,授权服务器如章节5.2返回一个错误答复。

一个示例的成功答复:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

4.4 客户端凭证许可

当客户端请求的是在客户端控制下的受保护资源,或者限制在先前由授权服务器布置的其他资源所有者的受保护资源(具体方法超出了这篇规范的讨论范围)时,客户端可以使用它的客户端凭证(或者其他支持的身份验证方法)来请求访问令牌。

客户端凭证许可类型必须仅被机密客户端使用。


图6: 客户端凭证流程

图6中阐述的流程包含如下步骤:

(A) 客户端在授权服务器上进行身份验证并从令牌端点请求一个访问令牌。

(B) 授权服务器身份验证客户端,如果有效,则分发一个访问令牌。

4.4.1 授权请求和答复

由于客户端身份验证被用作授权许可,不需要额外的授权请求。

4.4.2 访问令牌请求

客户端通过在HTTP请求体内使用“application/x-www-form-urlencoded”格式添加以下参数并使用UTF-8编码来请求令牌端点:

grant_type
	要求。 值必须被设为“client_credentials”。
scope
	可选。 如章节3.3描述的访问请求的scope。

客户端必须如章节3.2.1中所述与授权服务器进行身份验证。

例如,客户端使用传输层加密发起如下HTTP请求(额外的空行仅用于展示目的):

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=client_credentials

授权服务器必须对客户端进行身份验证。

4.4.3 访问令牌答复

如果访问令牌请求有效并且得到授权,授权服务器会如章节5.1所述分发一个访问令牌。不应该包含刷新令牌。如果客户端身份认证失败或者请求无效,授权服务器如章节5.2返回一个错误答复。

一个示例的成功答复:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "example_parameter":"example_value"
     }

4.5 扩展许可

客户端通过使用一个(由授权服务器定义的)绝对路径URI作为令牌端点"grant_type"参数的值,并按需添加任意参数,以使用一个扩展许可类型。

例如,为了使用如[OAuth-SAML2]定义的加密断言标记语言(SAML)2.0断言许可类型来请求一个访问令牌,客户端可以使用TLS发起如下HTTP请求(额外的空行仅用于展示目的):

     POST /token HTTP/1.1
     Host: server.example.com
     Content-Type: application/x-www-form-urlencoded

     grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Asaml2-bearer&assertion=PEFzc2VydGlvbiBJc3N1ZUluc3RhbnQ9IjIwMTEtMDU[...omitted for brevity...]aG5TdGF0ZW1lbnQ-PC9Bc3NlcnRpb24-

如果访问令牌请求有效并且得到授权,授权服务器会如章节5.1所述分发一个访问令牌以及可选的刷新令牌。如果客户端身份认证失败或者请求无效,授权服务器如章节5.2返回一个错误答复。

5 分发访问令牌

如果访问令牌请求有效并且被授权,授权服务器就会如章节5.1分发一个访问令牌和可选的刷新令牌。如果客户端身份认证失败或者请求失败了,授权服务器如章节5.2返回一个错误答复。

5.1 成功答复

授权服务器通过添加以下参数到HTTP答复体中,并答复200(OK)状态码,来分发访问令牌和可选的刷新令牌。

access_token
	要求。 由授权服务器分发的访问令牌。
token_type
	要求。如章节7.1所述,分发的令牌的类型。值大小写不敏感。
expires_in
	推荐。 以秒为单位的访问令牌生命周期。比如,值“3600”表明访问令牌将从生成答复起的一小时后过期。如果省略了,授权服务器应该由其他方法提供过期时间,或者文档化默认值。
refresh_token
	可选。 刷新令牌,可以如章节6所述,用于获取有同样授权许可的访问令牌。
scope
	如过和客户端请求的一致则是可选;否则,要求。如章节 3.3中描述的访问请求scope。

这些参数是使用[RFC4627]定义的"application/json"媒体类型编码在HTTP答复体中的。参数们被通过添加在最高结构层级,编码进JavaScript对象标识(JSON)结构。参数名和字符串值使用JSON字符串。数字值使用JSON数字。参数的顺序无所谓,可以随便改变。

授权服务器对于任何包含令牌、凭证或者其他敏感信息的答复中,必须包含值为"no-store"的HTTP答复头字段"Cache-Control"[RFC2616],以及值为"no-cache"的"Pragma"答复头字段[RFC2616]。

比如:

     HTTP/1.1 200 OK
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "access_token":"2YotnFZFEjr1zCsicMWpAA",
       "token_type":"example",
       "expires_in":3600,
       "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
       "example_parameter":"example_value"
     }

客户端必须忽略答复中不认得的值名。令牌以及其他从授权服务器接收的值的大小是为定义的。客户端应该避免假设值的大小。授权服务器应该文档化它分发的任何值的大小。

5.2 错误答复

授权服务器答复HTTP 400(错误请求)状态码(除非其他特定情况)并在答复中包含其他参数:

error
	要求。 以下之一的单个ASCII[USASCII]错误码:
	invalid_request
		请求缺少要求的参数,可能是不支持的参数值(不同于许可类型)、有参数给出超过一次,包含多个凭证,用到了不止一个身份认证客户端的机制,或者其他错误。
	invalid_client
		客户端身份认证失败(例如,不认识的客户端,没有带客户端身份凭证,或者不支持的身份认证方法)。授权服务器可能返回HTTP 401(未授权)状态码来表明支持哪些HTTP身份认证方案。如果客户端尝试经由“Authorization”请求头字段来身份验证,授权服务器必须答复HTTP 401(未授权)状态码并包含“WWW-Authenticate”答复头字段,匹配客户端使用的身份验证方案。
	invalid_grant
		提供的授权许可(例如,授权码,资源所有者凭证)或者刷新令牌是无效的,过期的,吊销的,不匹配授权请求中使用的重定向URI,或者是分发给另一个客户端的。
	unauthorized_client
		客户端不被授权使用这此授权许可类型。
	unsupported_grant_type
		授权许可类型不被授权服务器支持。
	invalid_scope
		请求的scope是无效的,未知的,格式错误的,或者超出了资源所有者许可的scope的。
	“error”参数的值绝不能包含超出字符集 %x20-21 / %x23-5B / %x5D-7E 的字符。
error_description
	可选。 人类可读的ASCII[USASCII]文本,提供额外的信息,用于协助客户端开发者理解发生的错误。
	“error_description”参数的值绝不能包含超出字符集 %x20-21 / %x23-5B / %x5D-7E 的字符。
error_uri
	可选。 一个定义了人类可读网页的URI,上面是关于错误的信息,用于提供客户端开发者关于错误的额外信息。
	“error_uri”参数的值必须遵从URI参考语法,并且绝不能包含超出字符集 %x21 / %x23-5B / %x5D-7E 的字符。

这些参数是使用[RFC4627]定义的"application/json"媒体类型编码在HTTP答复体中的。参数们被通过添加在最高结构层级,编码进JavaScript对象标识(JSON)结构。参数名和字符串值使用JSON字符串。数字值使用JSON数字。参数的顺序无所谓,可以随便改变。

例如:

     HTTP/1.1 400 Bad Request
     Content-Type: application/json;charset=UTF-8
     Cache-Control: no-store
     Pragma: no-cache

     {
       "error":"invalid_request"
     }

6 刷新一个访问令牌

如果授权服务器将一个刷新令牌分发给了客户端,客户端通过在HTTP请求体内使用“application/x-www-form-urlencoded”格式并使用UTF-8编码发送以下参数来构建一个刷新请求请求令牌端点:

grant_type
	要求。 值必须被设置为“refresh_token”。
refresh_token
	要求。 分发给客户端的刷新令牌。
scope
	可选。如章节 3.3中描述的访问请求scope。请求的scope绝不能包含资源所有者原先没有许可的scope,如果省略了,就当作是请求原先资源所有者许可的scope。

由于刷新令牌典型地是用于请求额外访问令牌的长效凭证,其被绑定到分发的客户端。如果客户端类型是机密,或者客户端被分发了客户端凭证(或者要求其他身份认证),客户端必须如章节3.2.1所述与授权服务器进行身份验证。

例如,客户端使用传输层加密发起如下HTTP请求(额外的空行仅用于展示目的):

     POST /token HTTP/1.1
     Host: server.example.com
     Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
     Content-Type: application/x-www-form-urlencoded

     grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

授权服务器必须:

  • 要求机密客户端或者其他被分发了客户端凭证(或要求其他身份验证)的客户端进行身份验证。
  • 如果包含了身份验证,验证客户端并确定这刷新令牌是分发给了这客户端,并且
  • 验证刷新令牌。

如果有效并且被授权,授权服务器如章节5.1分发一个访问令牌。如果请求验证失败或者无效,授权服务器如章节5.2返回一个错误答复。

授权服务器可能分发一个新刷新令牌,这时,客户端必须抛弃旧刷新令牌并替换为新的这个。授权服务器可能在分发新刷新令牌给客户端后撤销旧的那个。如果分发了一个新的刷新令牌,刷新令牌的scope必须与客户端在请求中带来的那个刷新令牌一致。

7 访问受保护的资源

客户端通过给资源服务器提供访问令牌来访问受保护的资源。资源服务器必须验证访问令牌,确保其未过期并且scope覆盖了请求的资源。资源服务器用来验证访问令牌的方法(以及任何错误答复)超出了这篇规范的讨论范围,但是通常需要资源服务器和授权服务器间的交互或协调。

客户端用访问令牌在授权服务器上认证的方法取决于授权服务器分发的访问令牌的种类。典型地,要使用HTTP “Authorization”请求头字段[RFC2617]带上访问令牌类型使用的规范定义的一个身份认证方案,比如[RFC6750]。

7.1 访问令牌类型

访问令牌类型给客户端提供了用于成功使用访问令牌请求受保护资源的信息(带着类型特定的属性)。如果客户端不理解令牌类型,它绝不能使用访问令牌。

例如,[RFC6750]中定义的“bearer”令牌类型通过简单地在请求中包含访问令牌字符串来使用:

     GET /resource/1 HTTP/1.1
     Host: example.com
     Authorization: Bearer mF_9.B5f-4.1JqM

而定义在[OAuth-HTTP-MAC]中的“mac”令牌类型通过分发一个消息授权码(MAC, Message Authentication Code)与用于签名HTTP请求特定组件的访问令牌来使用:

     GET /resource/1 HTTP/1.1
     Host: example.com
     Authorization: MAC id="h480djs93hd8",
                        nonce="274312:dj83hs9s",
                        mac="kDZvddkndxvhGRXZhvuDjEWhGeE="

以上示例仅用于阐述目的。建议开发者在使用前先读读[RFC6750]和[OAuth-HTTP-MAC]规范。

每个访问令牌类型定义都指定了要与“access_token”答复参数一同发给客户端的额外属性(如有)。它也定义当请求受保护资源时用于包含访问令牌的HTTP身份验证方法。

7.2 错误答复

如果资源访问请求失败了,资源服务器应该告知客户端这个错误。尽管指定这个错误答复超出了这篇规范的讨论范围,这篇文档在章节11.4中建立了一个通用错误值的注册表,通用错误值是要被OAuth令牌身份认证方案共享的。

主要为OAuth令牌身份认证设计的新身份认证方案应该定义一个提供错误状态码给客户端的机制,其中允许的错误值注册在由这篇规范建立的错误注册表。

这样的方案可能把有效错误码集合限制在注册值的子集。如果错误码使用一个命名参数返回,参数名应该是“error”。

其他能够用来OAuth令牌身份认证但主要不是为这目的设计的方案,可能以同样的行为绑定他们的错误值到注册表中。

新的身份认证方案可能选择也使用"error_description"和"error_uri"参数,以和这篇规范一致的行为来返回错误信息。

8 扩展性

8.1 定义访问令牌类型

访问令牌类型可以以两种方式之一定义:注册到访问令牌类型注册表中(按照章节11.1中的流程),或者使用一个唯一绝对路径URI作为其名字。

使用一个URI名的类型应该被限制为供应商专用的实现,不会被广泛应用,特定于使用其的资源服务器的实现细节。

所有其他类型必须被注册。类型名必须遵从type-name ABNF。如果类型定义包含一个新HTTP身份认证方案,类型名应该与HTTP身份认证方案名一致(如[RFC2617]中定义的)。令牌类型"example"被保留在示例中使用。

     type-name  = 1*name-char
     name-char  = "-" / "." / "_" / DIGIT / ALPHA

8.2 定义新端点参数

用于授权端点或令牌端点的新请求或响应参数被按照第 11.2 节中的过程在OAuth 参数注册表中定义和注册。

参数名称必须符合 param-name ABNF,并且参数值语法必须是明确定义的(例如,使用 ABNF,或引用现有参数的语法)。

     param-name  = 1*name-char
     name-char   = "-" / "." / "_" / DIGIT / ALPHA

未注册的特定于供应商的参数扩展通常不被普遍接受,并且特定于使用它们的授权服务器的实现细节,应该使用不太可能与其他注册值冲突的供应商特定前缀(例如,以’companyname_'开头)。

8.3 定义新的授权许可类型

可以通过给定一个唯一的绝对路径URI给grant_type参数使用,来定义新的授权许可类型。如果扩展的许可类型要求额外的令牌端点参数,他们必须如章节11.2注册再OAuth参数注册表。

8.4 定义新的授权端点答复类型

与授权端点一起使用的新答复类型被按照第 11.3 节中的过程在授权端点答复类型注册表中定义和注册。答复类型名称必须符合 response-type ABNF。

     response-type  = response-name *( SP response-name )
     response-name  = 1*response-char
     response-char  = "_" / DIGIT / ALPHA

如果一个答复类型包含一个或多个空格符(%x20),它被作为一个空格分隔的值列表来比较,值的顺序是无所谓的。仅能注册一种顺序的值集,这已经覆盖了所有其他排列了。

例如,答复类型“token code”不被这篇规范定义。然而,扩展可以定义和注册“token code”答复类型。一旦注册成功,“code token”就不能注册了,但两个值都表达同个答复类型。

8.5 定义额外的错误码

以防万一协议扩展(即,访问令牌类型、扩展参数或者扩展许可类型)要求额外的错误码来与授权码许可错误答复(章节4.1.2.1)、隐式许可错误答复(章节4.2.2.1),令牌错误答复(章节5.2)或者资源访问错误答复(章节7.2)一起使用,需要能定义新错误码。

如果扩展错误码是和一个注册的访问令牌类型、一个扩展许可类型或一个扩展许可类型结合使用,扩展错误码必须被注册(按照章节11.4中的过程)。与未注册的扩展一起使用的错误码可能被注册。

错误码必须遵从error ABNF,并如果可能,应以可识别名称作为前缀。例如,一个表明扩展参数“example”值无效的错误应该命名为“example_invalid”。

     error      = 1*error-char
     error-char = %x20-21 / %x23-5B / %x5D-7E

9 本地应用

本地(native)应用指安装和执行在资源所有者使用的设备上的客户端(即,桌面应用、原生移动手机应用)。本地应用要求特别考虑安全、平台能力和整个终端用户体验。

授权端点要求客户端和资源所有者的用户代理间的交互。原生应用可以调用一个外部用户代理,或者在应用内部嵌入一个用户代理。例如:

  • 外部用户代理 - 本地应用可以通过 在操作系统上注册一个scheme作为调用客户端的句柄使用重定向URI、人工复制黏贴凭证、运行一个本地web服务器,安装一个用户代理扩展,或者提供一个标识在客户端控制下放在服务端资源的重定向URI 来捕获来自授权服务器的答复,这样使得本地应用能够获取答复。
  • 嵌入式用户代理 - 本地应用通过直接与嵌入式用户代理通信,监控在资源加载时发出的状态变更,或者访问用户代理的cookie存储来获取答复。

当在外部或嵌入式用户代理中进行选择时,开发者应该考虑:

  • 外部用户代理可能提高完成率,由于资源所有者可能已经已经与授权服务器有过交互会话,这样就不用再次授权了。外部用户代理提供给用户其熟悉的终端用户体验和功能性。资源所有者可能也依赖用户代理的特性或者扩展来协助授权(例如,密码管理,2-factor设备阅读器)。
  • 一个嵌入式用户代理可能提高可用性,因为这样就不用切换上下文并打开新窗口了。
  • 一个嵌入式用户代理带来安全挑战,因为资源所有者在一个身份不明的窗口中进行身份验证,而无法访问大多数外部用户代理中可见的保护。一个嵌入式用户代理教育终端用户去信任身份不明的请求来身份认证(这使得网络诱骗攻击更容易发生)。

当在隐式许可类型和授权码许可类型间选择时,应该考虑以下:

  • 使用授权码许可类型的本地应用应该不使用客户端凭证来做这件事,由于本地应用无法保证客户端凭证的机密性。
  • 当使用隐式许可类型流程时,刷新令牌不会返回,这使得一旦访问令牌过期,就得重复授权过程。

10 安全考虑

作为一个灵活可扩展的框架,OAuth的安全考虑依赖许多因素。以下章节提供给实现人员安全准则,聚焦于章节2.1描述的三个客户端形态:web应用,基于用户代理的应用和本地应用。

一个综合的OAuth安全模型和分析,以及协议设计的背景在[OAuth-THREATMODEL]]中提供。

10.1 客户端身份认证

授权服务器给web应用客户端建立客户端凭证用于客户端身份认证。授权服务器被鼓励考虑强大的客户端身份认证方法,而不是客户端密码。web应用客户端必须确保客户端密码以及其他客户端凭证的机密性。

授权服务器绝不能绝不能为了客户端身份认证的目的将客户端密码或者其他客户端凭证分发给本地应用或者基于用户代理的应用客户端。授权服务器可能对在特定设备上的一个本地应用客户端的一个特定安装分发一个客户端密码或者其他凭证。

当不可能用客户端身份认证时,授权服务器应该采用其他方法来验证客户端的身份–例如,通过要求注册客户端重定向URI或者让资源所有者来确认其身份。一个有效的重定向URI不足以在请求资源所有者授权时验证客户端的身份,但是可以避免在获得资源所有者授权后,把凭证分发给伪造的客户端。

授权服务器必须考虑与未身份认证的客户端进行交互的潜在安全风险,并采取行动限制暴露其他凭证(例如,刷新令牌)给这种客户端。

10.2 客户端仿冒

如果被仿冒的客户端没有保证好自己凭证的机密性,一个恶意客户端可以冒充其他客户端, 并能访问受保护的资源。

授权服务器只要有可能,就必须对客户端进行身份认证。如果授权服务器由于客户端的特性,无法身份认证客户端,授权服务器必须要求客户端注册用于接受授权答复的所有重定向URI并使用其他方法保护资源所有者免于受受这些潜在恶意客户端的攻击。例如,授权服务器可以利用资源所有者来协助辨认客户端以及请求来源。

授权服务器应该强制要求资源所有者明确的授权,并提供给资源所有者关于客户端、请求的授权scope以及生命周期的信息。而审核信息确实处于当前客户端上下文中,并授权或者拒绝请求则是资源所有者的事情了。

授权服务器不应该在没有身份认证客户端或者依赖于其他方法的情况下,自动(即没有资源所有者主动交互地)处理重复的授权请求,以确保重复的请求来自于原来的客户端,而不是一个冒牌货。

10.3 访问令牌

访问令牌凭证(以及任何机密访问令牌属性)必须在传输和存储中被保持机密,并且仅在授权服务器,访问令牌有效的资源服务器,以及访问令牌被分发的客户端间分享。授权服务器必须仅使用章节1.6中描述的TLS来传输访问令牌凭证,如[RFC2818]中定义的。

当使用隐式许可类型,访问令牌在URI fragment中传输,这可能将它暴露给未授权者。

授权服务器必须确保访问令牌无法被未授权者生成、修改,或者通过猜测来产生有效的访问令牌。

客户端应该以最小所需scope来请求访问令牌。授权服务器在选择如何遵守所请求的scope时应当考虑客户端身份,并且可以分发权限少于请求的访问令牌。

本规范没有为资源服务器提供任何方法来确保给定客户端提供给它的访问令牌是由授权服务器分发给该客户端的。

10.4 刷新令牌

授权服务器可能分发刷新令牌给web应用客户端以及本地应用客户端。

刷新令牌必须在传输和存储中被保持机密,并且仅在授权服务器以及刷新令牌被分发的客户端间分享。授权服务器必须维持刷新令牌与它被分发的客户端间的绑定。刷新令牌必须仅使用章节1.6中描述的TLS来传输刷新令牌凭证,如[RFC2818]中定义的。

只要客户端身份能够认证,授权服务器必须验证刷新令牌与客户端身份间的绑定关系。当无法进行客户端身份验证,授权服务器应该采用其他方法来探测刷新令牌滥用。

例如,授权服务器可以采用刷新令牌轮转,即在每次访问令牌刷新答复中分发一个新的刷新令牌。前一个刷新令牌作废,但是仍然被授权服务器保留。如果一个刷新令牌泄漏了,随后由攻击者和合法客户端使用,它们中的一个会提供一个作废的刷新令牌,授权服务器就能意识到可能出问题了。

授权服务器必须确保刷新令牌无法被未授权者生成、修改,或者通过猜测来产生有效的刷新令牌。

10.5 授权码

授权码应该在加密通道上传输,如果重定向URI标识了一个网络资源,客户端应该在这个URI上使用TLS。由于授权码是仅由用户代理重定向传输的,它们有被用户代理历史记录和HTTP referrer头部泄漏的可能性。

授权码体现为一个纯文本承载凭证,用于验证在授权服务器上许可授权的资源所有者与返回给客户端以完成过程的资源所有者是同一个人。因此,如果客户端依赖授权码实现它自己的资源所有者认证,客户端重定向端点必须要求使用TLS。

授权码必须是短时效一次性使用的。如果授权服务器观测到多次请求尝试使用一个授权码去交换一个访问令牌,授权服务器应该尝试召回所有基于受攻击授权码已产生的访问令牌。

如果可以对客户端进行身份验证,授权服务器必须身份验证客户端并确保授权码是分发给了同个客户端。

10.6 授权码重定向URI操控

当使用授权码许可类型请求授权时,客户端可以通过"redirect_uri"参数指定一个重定向URI。如果一个攻击者可以操控重定向URI的值,这会导致授权服务器重定向资源所有者的用户代理到一个处于攻击者控制下的URI并给其授权码。

一个攻击者可以在一个合法的客户端上创建一个账号并发起授权流程。当攻击者的用户代理被发给授权服务器以许可访问时,攻击者抓取合法客户端提供的授权URI并替换客户端的重定向URI为其控制下的URI。攻击者然后欺骗受害者跟随被操纵的链接以授权访问合法客户端。

在授权服务器上,受害者代表合法且受信任的客户端被提示一个正常的、有效的请求,并授权该请求。然后受害者带着授权码被重定向到攻击者控制下的端点。攻击者通过使用客户端提供的原来的重定向 URI 向客户端发送授权码来完成授权流程。客户端与访问令牌交换授权代码并将其链接到攻击者的客户端帐户,该帐户现在可以访问受害者授权的受保护资源(通过客户端)。

为了免受这样的攻击,授权服务器必须确保用于获取授权码的重定向URI与在使用授权码交换访问令牌时提供的重定向URI一致。授权服务器必须要求公开客户端,并且应该要求机密客户端注册它们的重定向URI。如果一个重定向URI在请求中被提供,授权服务器必须验证它符合注册的值。

10.7 资源所有者密码凭证

资源所有者密码凭证许可类型通常是因为遗留或者迁移原因使用。它减少了由客户端存储用户名和密码的整体风险,但是没有消除将高权限凭证暴露给客户端的需要。

这个许可类型相较于其他许可类型有着更高的风险,因为它维持了密码反模式,这是这篇规范一直寻求避免的。客户端可能会滥用密码,密码也可能无意中被暴露给攻击者(例如,通过客户端保留的日志文件或者其他记录。)

另外,由于资源所有者控制不了授权过程(资源所有者的事在他将自己的凭证交给客户端后就结束了),客户端可以获取比资源所有者希望的scope更广的scope。授权服务器应该考虑由这种许可类型分发的访问令牌的scope和生命周期。

授权服务器和客户端应该最小化这种许可类型的使用,并且只要可能,就使用其他许可类型。

10.8 请求机密性

访问令牌、刷新令牌、资源所有者密码,以及客户端凭证绝不能被明文传输。授权码不应该被明文传输。

“state”和“scope”参数不应该包含以纯文本包含敏感的客户端或者资源所有者信息,由于它们可能被在非加密通道上传输,或者被不安全的存储。

10.9 确保端点权威性

为了避免中间人攻击,授权服务器必须要求发送到授权和令牌端点的所有请求都使用TLS,如[RFC2818]定义的。客户端必须如[RFC6125]定义的,验证授权服务器的TLS证书,并按照需求验证服务器的身份。

10.10 凭证猜测攻击

授权服务器必须防着攻击者猜测访问令牌、授权码、刷新令牌、资源所有者密码和客户端凭证。

攻击者猜中生成的令牌(以及其他不打算由最终用户处理的凭据)的概率必须小于或等于 2^(-128),并且应该小于或等于 2^(-160)。

授权服务器必须使用其他方式来保护旨在供最终用户使用的凭据。

10.11 网络钓鱼攻击

广泛的部署这个协议以及相似的协议可能让终端用户习惯于被重定向到另外的网站并被要求输入密码。如果终端用户在输入凭证前没有小心的认证这些网站的权威性,攻击者就可能利用这个习惯来倒取资源所有者的密码。

服务提供者应该尝试教育终端用户网络钓鱼攻击的风险并提供机制让终端用户能简单地确认他们站点的真实性。客户端开发人员应该考虑他们如何与用户代理(例如,外部、嵌入式)交互的安全隐患,以及最终用户验证授权服务器真实性的能力。

为了降低网络钓鱼攻击的危险,授权服务器必须在每个用于终端用户交互的端点上要求使用TLS。

10.12 跨站请求伪造攻击

跨站请求伪造(CSRF, Cross-site request forgery)是一种攻击,其中攻击者导致受害者终端用户的用户代理跟随恶意 URI(例如,提供给用户代理误导性链接、图像或重定向)到信任服务器(通常经由有效的会话 cookie建立)。

针对客户端重定向URI的CSRF攻击使得攻击者能够注入它的授权码或者访问令牌,导致客户端使用与攻击者的受保护资源相关的访问令牌,而不是受害者的。(例如,保存受害者的银行帐号信息到攻击者控制的受保护资源。)

客户端必须为它的重定向URI实现CSRF保护。这典型的实现是通过要求任何发给重定向URI端点的请求包含一个值,这个值将用户代理的身份认证状态绑定到请求。(例如,session cookie的哈希值用来身份认证用户代理)。客户端应该在发起授权请求时利用“state”请求参数来传递这个值给授权服务器。

一旦从终端用户处获得了授权,授权服务器就重定向终端用户的用户代理回客户端,在“state”参数中随带着要求的绑定值。这个绑定值使得客户端能够通过匹配绑定值到用户代理的身份认证状态来验证请求的有效性。这个用于防御CSRF的绑定值必须包含一个不可猜测的值(如章节10.10中描述的),并且用户代理的身份认证状态(例如会话cookie、HTML5本地存储)必须被保存在一个仅能被客户端和用户代理访问的地方(即,被同源策略保护)。

一次针对授权服务器的授权端点的CSRF攻击可能导致攻击者在没有牵连或通知终端用户的情况下,为恶意客户端获得终端用户的授权。

授权服务器必须为其授权端点实现CSRF保护,并确保恶意客户端无法在没有让资源所有者知道的情况下获得授权。

10.13 点击劫持攻击

在一次点击劫持(Clickjacking)攻击中,攻击者注册一个合法客户端,然后创建一个恶意站点,在其中放一个透明的iframe加载授权服务器的授权端点网页,放置在一堆假按钮的上方,这些假按钮被小心的放置在授权网页的重要的按钮的正上方。当终端用户点击一个误导人的可见按钮,终端用户实际上点击了授权页面上的一个不可见按钮(例如一个“授权”按钮)。这使得攻击者能够骗资源所有者许可攻击者的客户端进行访问,而终端用户却不知道这回事。

为了避免这种形式的攻击,在请求终端用户授权时,本地应用应该使用外部浏览器,而不是嵌入浏览器。对于大部分较新的浏览器,授权服务器可以使用(非标准的)"x-frame-options"头来阻止使用iframes。这个头有两个可能值,“deny”和“sameorigin”,一个是阻止任何framing,一个是阻止不同来源的站点的framing。对于较老的浏览器,可以使用JavaScript frame-busting技术,但是可能不是所有浏览器中都有效。

10.14 代码注入和输入验证

当输入或其他外部变量被应用程序未经净化地使用并导致对应用程序逻辑的修改时,就是发生了代码注入攻击。这可能使得攻击者能够访问应用程序设备或其数据,导致拒绝服务,或引入广泛的恶意副作用。

授权服务器和客户端必须净化(以及当可能时进行验证)收到的任何值–特别的,"state"和“redirect_uri”参数的值。

10.15 开放重定向器

授权服务器、授权端点以及客户端重定向端点可能会被错误地配置,并成了一个开放的重定向器。开放重定向器是指使用一个参数来不经验证地自动重定向用户代理到参数值指定位置的端点。

开放重定向器可以被用于网络钓鱼攻击,或被攻击者使用熟悉且受信任的目的地的 URI 授权组件来让最终用户访问恶意站点。另外,如果授权服务器允许客户端注册仅仅部分重定向URI,攻击者可以利用开放重定向器操作客户端构筑一个重定向URI使通过授权服务器的校验却将授权码或者访问令牌发送到攻击者控制下的端点。

10.16 在隐式流程中滥用访问令牌冒充资源所有者

对于使用隐式流程的公开客户端,这篇规范不为客户端提供任何方法来确定这访问令牌是分发给哪个客户端的。

一个资源所有者可能通过许可一个访问令牌给攻击者的冒充客户端,自愿委托对资源的访问。这可能是由于网络钓鱼,或者其他借口。一个攻击者也可能通过其他机制偷窃一个令牌,然后可能通过提供访问令牌给合法的公开客户端,试图冒充资源所有者。

在隐式流程中(response_type=token),攻击者可以轻易地在来自授权服务器的答复中替换掉令牌,把真正的访问令牌替换为先前分发给攻击者的。

服务器与依赖在反向通道中传递访问令牌来识别客户端用户的本地应用程序通信的服务器可能同样受到攻击者的攻击,该攻击者创建了一个可以注入任意被盗访问令牌的受感染应用程序。

任何假设仅仅资源所有者可以提供资源的有效访问令牌的公开客户端都易受这种类型的攻击。

这种类型的攻击可能将合法客户端上关于资源所有者的信息暴露给攻击者(恶意客户端)。这也将使得攻击者能够在合法客户端上执行与之前许可了访问令牌或者授权码的资源所有者相同权限的操作。

客户端上要怎么对资源所有者进行身份验证超出了这篇规范的讨论范围。任何使用委托终端用户给客户端进行授权的形式完成授权过程的规范(例如,第三方登入服务)绝不能在没有额外加密机制让客户端确定是否访问令牌是分发给它使用(例如,观众受限(audience-restricting)的访问令牌)的情况下使用隐式流程。

11 IANA 考虑

后略

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值