OAuth 2.0 原理介绍

最近在做对用户的认证及REST API的访问权限控制,需要用OAuth来实现第三方应用对我们API的访问控制。OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth在全世界得到广泛应用,目前版本是2.0版。本文对OAuth 2.0的应用场景、设计思路和运行流程做一个简明通俗的解释。

应用场景

OAuth 2.0 原理介绍_第1张图片

上图是一个典型的应用场景,一个游戏应用希望读取用户Facebook账号的用户名和头像作为该用户在游戏中的角色信息,用户为了避免自己重新输入用户名并上传头像,必须让游戏应用读取自己Facebook账号的一些信息。但是只有得到用户授权,Facebook才会同意让游戏应用读取这些信息。如何让游戏应用获得用户授权呢?传统方法是用户把自己的Facebook账号用户名和密码告诉游戏应用,然后由游戏服务器代表用户登陆Facebook服务器获取用户的信息,但是这种方法存在一些严重的安全问题:

  1. 游戏应用为了后续的服务,会保存用户的密码,这样很不安全。
  2. Facebook需要部署直接密码登录,而单纯的密码登录并不安全。
  3. 游戏应用拥有获取用户储存在Facebook所有资料的权力,用户无法限制游戏应用获得授权的范围和有效期。
  4. 用户只有修改密码,才能收回赋予游戏应用的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
  5. 只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

如何保证第三方应用能够安全可控的访问用户资源,这就是Oauth要解决的问题。

OAuth的思路

OAuth在第三方应用与服务提供商之间设置了一个授权层。第三方应用不能直接登录服务提供商,只能登录授权层,以此将用户与客户端区分开来。第三方应用登录授权层所用的令牌,与用户的密码不同。用户可以在登录授权的时候,指定授权层令牌的权限范围和有效期。
第三方应用登录授权层以后,服务提供商根据令牌的权限范围和有效期,向第三方应用开放用户资源。

协议流程

OAuth 2.0的运行流程如下图:
OAuth 2.0 原理介绍_第2张图片

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

上面六个步骤之中,B是关键,即用户怎样才能给予客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。
下面就介绍一下OAuth 2.0 的授权模式。

授权模式

客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式:

  1. 授权码模式(Authorization Code)
  2. 隐身模式(Implicit)
  3. 资源拥有者密码凭据模式(Resource Owner Password Credentials)
  4. 客户端凭据模式(Client Credentials)

其中授权码模式是功能最完整、流程最严密的授权模式。它的特点是通过客户端的后台服务器,与服务提供商的认证服务器进行互动。
下面着重介绍授权码模式,其他模式可参考附件PPT。

授权码模式

OAuth 2.0 原理介绍_第3张图片

上图是授权码模式的授权步骤:

(A)用户访问客户端后,客户端把用户导向认证服务器,认证服务器会返回一个授权页面,询问用户是否授权以及授权的资源
(B)用户选择是否给予客户端授权。
(C)假设用户给予授权,认证服务器会返回一个重定向请求,将用户导向客户端在A步骤指定的"重定向URI",同时附上一个授权码。
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

下面是上面这些步骤所需要的参数和实例:
步骤A,用户访问客户端,客户端将用户导向认证服务器,包含以下参数:

  • response_type:表示授权类型,必选项,此处的值固定为”code”
  • client_id:表示客户端的ID,必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值

下面是一个实例:

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

步骤B,用户在认证服务器登陆授权。

步骤C,假设用户给予授权,认证服务器将用户导向客户端事先指定的重定向URI,同时附上一个授权码。请求包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和“重定向URI”是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

下面是一个实例:

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

步骤D,客户端收到授权码,附上“重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台服务器上完成,对用户不可见。请求包含以下参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为”authorization_code”。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
  • client_id:表示客户端ID,必选项。

下面是一个实例:

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

步骤E,认证服务器核对授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。认证服务器发送的HTTP回复包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

下面是一个实例:

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" 
}

从返回头信息可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。token_type表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。

以上为授权码模式的详细授权过程,如果希望了解其他授权模式,请详见附件PPT。

安全机制

OAuth 2.0 协议在设计时考虑了很多安全因素,下面介绍授权码模式的一些安全机制:

  1. 利用更新令牌来延长令牌授权时间。
    为了保证安全性,授权的令牌时间不可过长,但是一些第三方应用需要长时间保持资源访问状态,为此,OAuth 2.0 提供了更新令牌机制,一方面使令牌授权时间不会过长,另一方面保证了第三方应用访问资源的连贯性。更新令牌机制仅在授权码模式和资源拥有者密码凭据模式中提供,因为这两种授权机制相比另外两种更安全。
  2. 第三方应用需要在授权服务器上注册和认证。
    OAuth 2.0 协议默认浏览器是一个不安全的环境,所以在授权码模式授权过程中,用户给予授权后,认证服务器不是直接返回访问令牌,而是返回认证码,并通过浏览器重定向给第三方应用。第三方应用需要用认证码换取访问令牌,而换取步骤需要认证服务器认证第三方应用身份并且不通过浏览器,以此保证授权过程的安全性。
  3. 获取认证码请求中,加入state参数防止CSRF攻击。
    在第三方应用把用户重定向到认证服务器以获取认证码的请求中,需要加入state参数,且认证服务器要返回相同的state参数给第三方应用。CSRF攻击者要想诱导用户授权并插入自己的认证码,且被第三方应用接收,就需要猜出该state参数,这大大增加了CSRF攻击的难度。

总结

目前很多互联网公司都提供了自己的开放平台使第三方应用接入。开源项目中也有很多框架提供了OAuth的实现,例如Spring Security OAuth,Apache Oltu等。使用OAuth协议能够很好的保证第三方应用访问用户数据的安全性。


参考:理解 OAuth 2.0

你可能感兴趣的:(技术)