OAuth 2.0 / RCF6749 协议解读

  OAuth是第三方应用受权(Authorization)的开放标准,目前最新版本是2.0,如下将要介绍的内容和概念主要来源于该版本。 恐篇幅太长,OAuth 的诞生背景就不在这里赘述了,可参考 The OAuth 2.0 Authorization Frameworkhtml

  四种角色定义git

  1. Resource Owner:资源全部者,即终端用户
  2. Resource server:资源服务器,即提供资源存储访问一方
  3. Client:一般指第三方应用
  4. Authorization server:受权服务器

  协议端点(URI):OAuth给受权过程定义了Authorization、Token和Redirection三种端点。Authorization端点用来完成用户受权,在受权码模式(Authorization Code)隐含模式(Implicit)下被用到;Token端点用来交换与获取access token,不能包含fragment(hash),在隐含模式(Implicit)下则无需提供该端点;Redirection端点用来接收受权凭证,Public客户端或者Implicit受权的Confidential客户端必须注册其Redirection端点。promise

  客户端类型:OAuth根据是否可以进行安全认证定义了两种客户端类型:机密型客户端(Confidential)和公开型客户端(Public)。其中机密型客户端有Web应用,公开型客户端包括User Agent Based和Native应用。客户端的类型注册时肯定,不能由受权服务器假定。若是一套应用包含多个不一样类型的客户端,这些不一样部分应分开单独注册。浏览器

  客户端认证(Client Authentication):客户端认证当知足受权服务器的安全要求,对机密型客户端的认证可依赖受权服务器发布的认证凭证(好比Password, Public/Private密钥对),而要对公共客户端进行认证极可能是不可靠的。客户端在每次请求中只能使用一种认证方法,若是客户端持有Password,可采用HTTP Basic认证或request-body传递身份凭证参数方法。客户端认证带来的益处:安全

  1. 强制绑定Refresh Token或Authorization Code到客户端
  2. 经过禁用或修改其凭证来快速恢复沦陷客户端
  3. 按期凭证轮换,更容易实现认证管理

  访问令牌(Access Token)是什么?Access Token是访问被保护资源的凭证,一个用来代表被授予权限的字符串,能够是一种可取回受权信息的标识,也能够自包含受权信息于内。可参考 RFC6750 - OAuth 2.0 Bearer Token Usage 。服务器

  更新令牌(Refresh Token)是什么?当Access Token无效或过时后,客户端将使用Refresh Token来请求受权服务器更新Access Token,除此而外别无他用。一般Refresh Token是受权服务器在发布新Access Token的同时可选发布的,与客户端绑定并长期有效,可是只有受权码模式(Authorization Code)用户密码模式(Resource Owner Password Credentials)支持Refresh Token。受权服务器须执行以下操做:cookie

  1. 对于认证型客户端,要求进行认证
  2. 若是请求中包含客户端认证,则执行认证流程,还要保证Refresh Token是发布给认证客户端的
  3. 验证Refresh Token是否有效

  Transport Layer Security (TLS):受权服务器和资源服务器都必须实现TLS,至于客户端最好也实现TLS。若是客户端没有实现TLS,受权服务器在发出重定向以前应向用户发出安全告警信息。session

  OAuth受权的基本流程以下app

  

  1. 用户打开客户端之后,客户端要求用户给予受权
  2. 用户赞成给予客户端受权
  3. 客户端使用上一步得到的受权,向受权服务器申请令牌
  4. 受权服务器对客户端进行受权之后,确认无误,赞成发放令牌
  5. 客户端使用令牌,向资源服务器申请获取资源
  6. 资源服务器确认令牌无误,赞成向客户端开放资源

  OAuth针对不一样场景详细定义了四种受权模式:受权码模式(Authorization Code)、隐含模式(Implicit)、用户密码模式(Resource Owner Password Credentials)和客户端证书模式(Client Credentials)。另外,你也可使用其余扩展模式。ide

 

一. 受权码模式(Authorization Code)

  受权码模式是流程最严密的受权模式,可是若是被用于Public客户端受权,因为该客户端不能持有客户端证书,所以没法进行身份认证。

  • 流程解析: 
    1. 用户访问客户端,后者将前者导向受权服务器
    2. 用户选择是否给予客户端受权
    3. 假设用户给予受权,受权服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个受权码
    4. 客户端收到受权码,附上早先的"重定向URI",向受权服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见
    5. 受权服务器核对了受权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)或者更新令牌(refresh token)

  该流程中客户端先获取受权码再交换访问令牌,彷佛获取受权码显得多余?其实受权码除了表明受权范围以外,还避免了暴露访问令牌于用户端

The authorization code provides a few important security benefits,such as the ability to authenticate the client, as well as the transmission of the access token directly to the client without passing it through the resource owner's user-agent and potentially exposing it to others, including the resource owner

 

二. 隐含模式(Implicit)

  受权码模式的简化版,跳过了"受权码"这一步,可适用于在浏览器中实现的应用,访问令牌暴露于用户端;在该模式下,受权服务器不会认证客户端,不能使用Refresh Token,一旦Access Token过时,须要从新进行受权处理;隐含模式是一个基于redirection的流,在某些状况下,客户端身份是能够经过redirection URI来验证的。在受权码模式可用的状况下,应权衡隐含模式的便利性和安全性。

  • 流程解析
    1. 客户端将用户导向认证服务器
    2. 用户决定是否给于客户端受权
    3. 假设用户给予受权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌
    4. 浏览器向Web-Hosted服务器发出请求,其中不包括上一步收到的Hash值
    5. Web-Hosted服务器返回一个网页,其中包含的代码能够获取Hash值中的令牌
    6. 浏览器执行上一步得到的脚本,提取出令牌
    7. 浏览器将令牌发给客户端

  • 流程参数解释:此处再也不详述,可参考理解OAuth 2.0 或 RFC6749

 

三. 用户密码模式(Resource Owner Password Credentials)

  用户向客户端提供本身的用户名和密码,客户端使用这些信息向受权服务器索要受权,但不得保存用户的密码。须在用户对客户端高度信任(好比客户端是操做系统的一部分,或者由一个著名公司出品,或者客户端是本公司出品),而认证服务器没法在其余受权模式下完成受权的状况下,才能考虑使用这种模式。

  • 流程解析
    1. 用户向客户端提供用户名和密码
    2. 客户端将用户名和密码发给认证服务器,向后者请求令牌
    3. 认证服务器确认无误后,向客户端提供访问令牌

 

四. 客户端证书模式(Client Credentials)

  顾名思义,客户端模式不是针对单个用户的受权,而是针对客户端受权,适用于受保护资源已经处于客户端控制之下(至关于资源全部者)或者受权服务器已经预先配置好客户端访问权限的的状况。

  • 流程解析
    1. 客户端向认证服务器进行身份认证,并要求一个访问令牌
    2. 认证服务器确认无误后,向客户端提供访问令牌

  • 流程参数解释:此处再也不详述,可参考理解OAuth 2.0 或 RFC6749

 

五. 受权模式选择

  • 本公司出品应用通常适用用户密码模式(Resource Owner Password Credentials)
  • Web应用通常适用受权码模式(Authorization Code)
  • Native应用通常适用受权码模式(Authorization Code)或隐含模式(Implicit):Native应用指安装、运行在用户设备上的客户端,包括桌面应用、手机客户端等
    When choosing between the implicit grant type and the authorization code grant type, the following should be considered:
    
    . Native applications that use the authorization code grant type SHOULD do so without using client credentials, due to the native application's inability to keep client credentials confidential.
    . When using the implicit grant type flow, a refresh token is not returned, which requires repeating the authorization process once  the access token expires.
  • User Agent Based应用通常适用隐含模式(Implicit)

  • 机器对机器通常适用客户端证书模式(Client Credentials) 

 

六. OAuth不是认证协议

OAuth消费认证(Authentication)而不提供认证,所以OAuth必须结合第三方认证协议如 OpenID Connect:OAuth 2.0协议之上的简单身份层 才可以使用。但OAuth协议中确实有些内容说的就是认证事件,给人的感受就是它已定义了认证流程,固然也就算是有效的认证协议了,这是很容易让人误解的;其实啊,定义认证流根本就不是OAuth的题中之意(好比用户注册这个认证流中的重要环节就不是OAuth所关心的内容,因此也就未曾定义)。下边的引文来自 The OAuth 2.0 Authorization Framework :

Before initiating the protocol, the client registers with the
authorization server.  The means through which the client registers
with the authorization server are beyond the scope of this
specification but typically involve end-user interaction with an HTML
registration form. 

只是认证和受权硬生生地割裂开来,井水不犯河水是不可能的,因此OAuth里边也只是简单地提到了与受权流相关的认证流要害节点以使受权流的定义完整,而没有详细定义认证流,这也是本人刚开始认为OAuth是一个弱认证受权协议的缘由。下边的引用文字来自 User Authentication with OAuth 2.0

OAuth 2.0 is not an authentication protocol.

an OAuth process does usually include several kinds of authentication in its process:

the resource owner authenticates to the authorization server in the authorization step,

the client authenticates to the authorization server in the token endpoint, and there may be others.

The existence of these authentication events within the OAuth protocol does not translate to the

Oauth protocol itself being able to reliably convey authentication.

假如OAuth能够彻底抛弃所涉及的任何认证流部分,也就不会有人认为OAuth也是认证协议了,而一个完整的认证协议应该是这样的:

Authentication in the context of a user accessing an application tells an application who

the current user isand whether or not they're present. A full authentication protocol will probably

also tell you a number of attributes about this user, such as a unique identifier, an email address,

and what to call them when the application says "Good Morning". Authentication is all about the

user and their presence with the application, and an internet-scale authentication protocol needs

to be able to do this across network and security boundaries.

  

七. 采用OAuth认证常见陷阱

  • Access Token做为访问受保护的资源身份认证的证实:Token应该包含Client可理解和解析的结构,如同时使用Client可理解和解析ID Token。
  • Access Token做为访问UserInfo API身份认证的证实:一般在用户不存在后,Access Token一般还会存在很长时间,若是一个Client想要确保身份认证是有效的,那么简单的使用Access Token获取用户信息是不够的。
  • Access Token注入:这可能会发生在使用Implicit流程中,而且Client不正确使用state参数的时候;对此可使用Authorization Code来缓解这一点,而且只能经过受权服务器的Token API并使用一个state的值来避免被攻击者猜中。
  • Access Token缺少Client受众限制:经过将Client的认证信息与Client能够识别和验证的标识符一块儿传递给Client,能够缓解此问题,从而容许客户端区分自身的身份认证与另外一应用程序的身份认证。
  • 对UserInfo API响应结果注入无效的用户信息:若是攻击者可以拦截或者替换来自Client的一个调用,它可能会改变返回的用户信息,而客户端却没法感知这一状况;对此可经过在身份认证协议过程当中(好比跟随OAuth的Token的颁发过程)直接从身份提供程序中获取身份认证信息,并经过可校验的签名保护身份认证信息,能够缓解这一问题。
  • 不一样身份认证提供商实现了不一样的身份认证协议:基于OAuth 身份(identity)API的最大问题在于,即便使用彻底符合OAuth的机制,不一样的身份认证提供程序不可避免的会使用不一样方式实现身份(identity)API。OAuth定义了一个没有特定格式的token,一个没有通用范围的access token,而且没有解决受保护资源如何验证access token。

 

八. 安全风险

  • 客户端认证(Client Authentication):对Public客户端进行认证极可能是不可靠的,受权服务器能够尝试使用redirection URI或征募用户来验证客户端身份
       The authorization server MUST NOT issue client passwords or other
       client credentials to native application or user-agent-based
       application clients for the purpose of client authentication.  The
       authorization server MAY issue a client password or other credentials
       for a specific installation of a native application client on a
       specific device.
       ......
       A valid
       redirection URI is not sufficient to verify the client's identity
       when asking for resource owner authorization but can be used to
       prevent delivering credentials to a counterfeit client after
       obtaining resource owner authorization.
  • 更新令牌(Refresh Tokens):受权服务器能够给Web客户端和Native客户端发布Refresh Token。Refresh Token在整个生命周期中都应该保持机密性,不能泄露给任何无关的第三方;Refresh Token必须与客户端身份相绑定;Refresh Token不能未获受权而被生成、修改、猜想产生

      the authorization server could employ refresh token
       rotation in which a new refresh token is issued with every access
       token refresh response.  The previous refresh token is invalidated
       but retained by the authorization server.  If a refresh token is
       compromised and subsequently used by both the attacker and the
       legitimate client, one of them will present an invalidated refresh
       token, which will inform the authorization server of the breach
  • 受权码(Authorization Codes):受权码有效期短,单一用途

       If the
       authorization server observes multiple attempts to exchange an
       authorization code for an access token, the authorization server
       SHOULD attempt to revoke all access tokens already granted based on
       the compromised authorization code.
  • 跨站请求伪造(Cross-Site Request Forgery):一同发送一个non-guessable state请求参数可用来防止CSRF
       A CSRF attack against the client's redirection URI allows an attacker
       to inject its own authorization code or access token, which can
       result in the client using an access token associated with the
       attacker's protected resources rather than the victim's (e.g., save
       the victim's bank account information to a protected resource
       controlled by the attacker).
    
       The client MUST implement CSRF protection for its redirection URI.
       This is typically accomplished by requiring any request sent to the
       redirection URI endpoint to include a value that binds the request to
       the user-agent's authenticated state (e.g., a hash of the session
       cookie used to authenticate the user-agent).  The client SHOULD
       utilize the "state" request parameter to deliver this value to the
       authorization server when making an authorization request.
  • 点击劫持(Clickjacking)
      To prevent this form of attack, native applications SHOULD use
       external browsers instead of embedding browsers within the
       application when requesting end-user authorization.  For most newer
       browsers, avoidance of iframes can be enforced by the authorization
       server using the (non-standard) "x-frame-options" header.  This
       header can have two values, "deny" and "sameorigin", which will block
       any framing, or framing by sites with a different origin,
       respectively.  For older browsers, JavaScript frame-busting
       techniques can be used but may not be effective in all browsers

 

九. 相关参考

相关文章
相关标签/搜索