安全系列之二:OAuth2.0协议

本文提取出OAuth2.0规范RFC6749的主要内容,部分内容从文档复制出来,给大家讲讲第三方授权背后的故事。

先是举个知乎的QQ登录授权的例子,然后讲四种授权方式,两种令牌,接着是看看协议流程,分析知乎的QQ登录授权请求响应报文解释OAuth2.0协议,最后简单看看QQ提供第三方授权的API加深理解。

先打个预防针,在讲解四种授权,两种令牌时大家可能会有点不懂,但是跟随着协议流程走就懂了。

如果觉得排版不好,可以访问我的博客。TAT

blog.bensonlin.me

如果觉得写得不错,欢迎推荐,关注我和follow我的github(我的主页里)。

什么是 OAuth

Open Authorization的缩写,即开放授权协议

OAuth 的授权使应用无需涉及另一方应用的帐号信息(如用户名与密码),只需要通过授权就可以另一方应用的信息,保证了安全性,不会泄露用户名密码。

而整个流程要怎么做才能保证安全呢,该协议定义了规则。

更多的定义可以自己查看OAuth的维基百科

举个栗子

第一步:当然是上知乎官网登录,点击QQ头像作为QQ登录

 图1

第二步:登录QQ并授权,可以看到右边是QQ授权给知乎的内容,获取我们的昵称,头像和性别等信息。输入用户名密码登录,可以看到按钮显示的是登录并授权,也就是是点击后就已经说明我们同意让知乎获取我们的这些个人信息。

 图2

因为我已经登录了,所以直接点上面的QQ头像(头像就是多啦A梦)直接授权。

 图3

第三步:登录授权成功,可以在知乎的首页看到你的信息(还需要补充知乎的个人信息作为新用户注册)

 图4

注意:有的网站授权,是先登录后,进入另一个页面然后再点击授权的。

PS:记住图的编号,后面分析用到

下面将进入正题,首先是上面涉及的几个角色,然后是协议流程等

几个角色

前提:知乎要用QQ登录,使用QQ的头像和昵称:

  • 资源所有者(Resource Owner):能够许可受保护资源访问权限的实体。也就是拥有QQ资源(头像/昵称)的,也就是我们。
  • 资源服务器(Resource Server):托管受保护资源的服务器,能够接收和响应使用访问令牌对受保护资源的请求。也就是某个放置头像信息的QQ服务器
  • 客户端(Client):使用资源所有者的授权代表资源所有者发起对受保护资源的请求的应用程序。也就是正在使用的知乎
  • 授权服务器(Authorization Server):在成功验证资源所有者且获得授权后颁发访问令牌给客户端的服务器。可以和资源服务器是同一台服务器,也可以是分离的个体。这里假设也是QQ服务器本身。

还有一个角色是资源所有者的用户代理(User Agent),一般就是我们的Web浏览器,我们需要浏览器作为代理才能够进行操作

四种授权方式

本规范定义了四种许可类型——授权码、隐式许可、资源所有者密码凭据和客户端凭据——以及用于定义其他类型的可扩展性机制。其中授权码是我们最常用的,因此单独讲授权码方式,其它类型详情可以自行下载RFC6749文档查看,下载地址在这里,搜索自己想要的文档,然后右键另存为下载即可

  • 授权码:授权码通过使用授权服务器作为客户端与资源所有者的中介而获得。客户端不是直接从资源所有者请求授权,而是引导资源所有者至授权服务器授权服务器之后引导资源所有者带着授权码回到客户端。在引导资源所有者携带授权码返回客户端前,授权服务器会鉴定资源所有者身份并获得其授权。由于资源所有者只与授权服务器进行身份验证,所以资源所有者的凭据不需要与客户端分享。授权码提供了一些重要的安全益处,例如验证客户端身份的能力,以及向客户端直接的访问令牌的传输而非通过资源所有者的用户代理来传送它而潜在暴露给他人(包括资源所有者)。
  • 隐式许可:在隐式许可流程中,不再给客户端颁发授权码,取而代之的是客户端直接被颁发一个访问令牌(作为资源所 有者的授权),授权服务器不对客户端进行身份验证。这种许可类型是隐式的,因为没有中间凭据(如授权码)被颁发(之后用于获取访问令牌)。
  • 资源所有者密码凭据:资源所有者密码凭据(即用户名和密码),可以直接作为获取访问令牌的授权许可。这种凭据只能应该 当资源所有者和客户端之间具有高度信任时(例如,客户端是设备的操作系统的一部分,或者是一个高度特权应用程序),以及当其他授权许可类型(例如授权码)不可用时被使用。
  • 客户端凭据:当授权范围限于客户端控制下的受保护资源或事先与授权服务器商定的受保护资源时客户端凭据可以被 用作为一种授权许可。典型的当客户端代表自己(客户端也是资源所有者)或者基于与授权服务器事先商定的授权请求对受保护资源的访问权限时,客户端凭据被用作为授权许可。

可以看到,授权码模式(authorization code)是功能最完整、流程最严密的授权模式。

两个令牌

  • 访问令牌(access token):访问令牌是用于访问受保护资源的凭据(如知乎拿访问令牌访问受保护的我们的昵称和头像等)。访问令牌是一个代表授权服务器向客户端颁发的授权的字符串。该字符串通常对于客户端是不透明的。令牌代表了访问权限的由资源所有者许可并由资源服务器和授权服务器实施的具体范围和期限。(不透明的意思都知道吧,就是客户端(知乎服务器)能够得到访问令牌,因为它要根据这个令牌去获取QQ的个人信息。)
  • 刷新令牌由授权服务器颁发给客户端,用于在当前访问令牌失效或过期时,获取一个新的访问令牌,或者获得相等或更窄范围的额外的访问令牌(访问令牌可能具有比资源所有者所授权的更短的生命周期和更少的权限)。颁发刷新令牌是可选的,由授权服务器决定。对客户端也是不透明的

(授权码许可)协议流程

+----------+
| Resource |
|   Owner  |
|          |
+----------+
     ^
     |
    (B)
+----|-----+           Client Identifier      +---------------+
|         -+----(A)-- & Redirection URI ----> |               |
|   User-  |                                  | Authorization |
|   Agent -+----(B)-- User authenticates ---> |     Server    |
|          |                                  |               |
|         -+----(C)-- Authorization Code ---< |               |
+-|----|---+                                  +---------------+
  |    |                                          ^      v
  (A) (C)                                         |      |
   |   |                                          |      |
   ^   v                                          |      |
+---------+                                       |      |
|         |>---(D)-- Authorization Code ----------‘      |
|  Client |          & Redirection URI                   |
|         |                                              |
|         |<---(E)----- Access Token --------------------‘
+---------+       (w/ Optional Refresh Token)

(A)客户端通过向授权端点引导资源所有者的用户代理开始流程。客户端包括它的客户端标识、请求范围、本地状态和重定向 URI,一旦访问被许可(或拒绝)授权服务器将传送用户代理回到该URI。

(B)授权服务器验证资源拥有者的身份(通过用户代理),并确定资源所有者是否授予或拒绝客户端的访问请求。

(C)假设资源所有者许可访问,授权服务器使用之前(在请求时或客户端注册时)提供的重定向URI重定向用户代理回到客户端。重定向 URI 包括授权码和之前客户端提供的任何本地状态。

(D)客户端通过包含上一步中收到的授权码从授权服务器的令牌端点请求访问令牌。当发起请求时,客户端与授权服务器进行身份验证。客户端包含用于获得授权码的重定向 URI 来用于验证。

(E)授权服务器对客户端进行身份验证,验证授权代码,并确保接收的重定向 URI 与在步骤(C)中用于重定向客户端的 URI 相匹配。如果通过,授权服务器响应返回访问令牌与可选的刷新令牌(如果原来的访问令牌过期了,而授权服务器又允许发送新的令牌,就会携带过去)

其他的协议流程可以查看RFC文档

解释知乎的QQ授权

注意结合上面的协议流程看分析:

  1. 首先,用户点击QQ登录时,知乎服务器会帮我们重定向到QQ的第三方授权服务器上页面上(图3)请求授权(可以看到,浏览器的地址是qq的地址,也就是说不会泄露QQ的密码给知乎,需要注意的是,这个链接需要使用https协议,因为涉及用户登录的密码),同时,跟随一个重定向URL指向知乎服务器的某个地址,我们点击授权后(图3),授权成功,重定向到知乎指定的URL并返回授权码(可以在URL看到)
  2. 接着知乎服务器发送同一个重定向URL和授权码请求授权服务器的访问令牌,最后如果QQ服务器校验没有问题,返回访问令牌,最后知乎服务器调用QQ提供的API,附带访问令牌获取用户的信息

为什么要分成两点呢?因为第一点我们可以容易的抓取请求响应报文得到,而获取访问令牌的过程对资源所有者(我们用户)是透明的,也就是说我们不会看到访问令牌,只有知乎服务器得到了访问令牌;其实看不到也不应该让资源所有者看到,否则就不安全了,因为谁都可以用访问令牌到访问我们的信息

那到底整个过程的细节是怎样的呢?咱们开始分析请求响应包

请求响应包和参数分析

这里使用Fiddler抓包工具,去除了某些头部,注意结合上面讲的内容;为了方便看报文,对其进行了换行处理;

重点关注:请求地址,响应状态值,Location;请求和响应过程中的参数下一小节分析

第一步:(知乎主页点击QQ登录)

请求报文:直接请求到QQ服务器,知乎希望得到的信息放到URL中。 GET请求中的关键参数有scope, state, redirect_uri, client_id, response_type

GET https://graph.qq.com/oauth2.0/authorize?
    scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share
    &state=8821ffbf09c3ff9c401fe404aa7fcaf7
    &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn
    &response_type=code
    &client_id=100490701 HTTP/1.1
Host: graph.qq.com
Referer: https://www.zhihu.com/

响应报文:响应302重定向到Location所在URL,也就是图3的页面,第二步的授权请求就是这里的Location值,当点击授权后表示用户允许QQ将部分个人信息交给知乎,因此知乎将真正得到这些权限。

HTTP/1.1 302 Moved Temporarily
Location: https://graph.qq.com/oauth/show?which=Login
    &display=pc
    &scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share
    &state=8821ffbf09c3ff9c401fe404aa7fcaf7
    &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn
    &response_type=code
    &client_id=100490701

第二步:授权请求和授权响应(点击同意登录并授权)

授权请求

关键参数有scope, state, redirect_uri, client_id, response_type

请求报文

POST https://graph.qq.com/oauth2.0/authorize HTTP/1.1
Host: graph.qq.com
Referer: https://graph.qq.com/oauth/show?which=Login
    &display=pc
    &scope=get_user_info%2Cget_info%2Cadd_t%2Cadd_pic_t%2Cget_other_info%2Cget_fanslist%2Cget_idollist%2Cadd_idol%2Cadd_share
    &state=8821ffbf09c3ff9c401fe404aa7fcaf7
    &redirect_uri=https%3A%2F%2Fwww.zhihu.com%2Foauth%2Fcallback%2Fqqconn
    &response_type=code
    &client_id=100490701
  • response_type:必选,固定是”code”
  • client_id:必选,是授权服务器颁发给已注册客户端客户端标识,也就是说知乎开发人员到QQ处申请表示希望通过QQ授权接入,QQ同意后会给知乎(client)一个唯一的标识,这样以后授权登录时,QQ方(授权服务器)就知道哪个应用正在请求接入
  • scope:可选,表示知乎希望从QQ上得到用户的什么权限。为什么第一步重定向要附带scope,因为为了防止我们点击授权时,有人恶意修改了URL,导致授权的内容变化了,有了第一步,QQ服务器能先知道需要什么权限(参数内容是get_user_info之类的内容,可以看到图2中打钩的选项其实就是根据scope得到的),保存在QQ服务器中,而如果点击授权后,传到服务器的scope内容变了,那么肯定是有人修改了scope,授权将失败,保证了安全性。
  • redirect_uri:可选,知乎希望跳转的URL,指向自己网站的位置,同样的,需要和第一步中的redirct_url相同,理由与scope相同
  • state:推荐的(应认为是必需的),客户端用于维护请求和回调之间的状态的不透明的值。当重定向用户代理回到客户端时,授权服务器包含此值。该参数应该用于防止如跨站点请求伪造CSRF

授权响应

响应报文:重定向到Location上(redirect_url),也就是回到知乎,关键参数是code, state

HTTP/1.1 302 Moved Temporarily
Location: https://www.zhihu.com/oauth/callback/qqconn?
    code=D38858BD4FE6058A48E461663ECB3CC3
    &state=8821ffbf09c3ff9c401fe404aa7fcaf7
  • code:必需的。授权服务器生成的授权码。授权码必须在颁发后很快过期以减小泄露风险。推荐的最长的授权码生命周期是 10 分钟。客户端不能使用授权码超过一次。如果一个授权码被使用一次以上,授权服务器必须拒绝该请求并应该撤销(如可能)先前发出的基于该授权码的所有令牌。授权码与客户端标识和重定向 URI 绑定。
  • state:必需的,若“state”参数在客户端授权请求中提交。则返回同一个值。

第三步:访问令牌请求和响应(知乎程序内部请求获取令牌)

请求获取token,最后访问用户的头像,昵称等信息

这一步对我们是透明的,我们看不到,其实就是简单的调用API调用获取,关键参数有grant_type, client_id, client_secret, code, redirect_uri

访问令牌请求

下一小节有QQ API

  • grant_type:必需的。值必须被设置为“authorization_code”。
  • code:从授权服务器收到的授权码。
  • redirect_uri:必需的,必须和第一步请求时的redirect_uri相同。
  • client_id:必需的

授权服务器必须:

  • 要求机密客户端或任何被颁发了客户端凭据(或有其他身份验证要求)的客户端进行客户端身份验证,
  • 若包括了客户端身份验证,验证客户端身份,
  • 确保授权码颁发给了通过身份验证的机密客户端,或者如果客户端是公开的,确保代码颁发给了请求 中的“client_id”,
  • 验证授权码是有效的,并
  • 确保给出了“redirect_uri”参数,若“redirect_uri”参数如 4.1.1 所述包含在初始授权请求中,且若包含,确保它们的值是相同的。

访问令牌响应

响应:关键参数有access_token, refresh_token

如果访问令牌请求是有效的且被授权,授权服务器颁发访问令牌以及可选的刷新令牌。如果请求客户端身份验证失败或无效,授权服务器返回错误响应。

QQ API加深理解

QQ接入API

state 的理解

攻击方式

假设 Alice 访问 知乎网站(Client)请求 QQ 登录授权(图1), 知乎 请求 QQ(授权服务器) 授权以获取 Alice 的信息,然后被重定向到 QQ服务器上(图2),此时知乎绑定了当前是Alice用户要进行QQ登录授权(假设用cookie绑定,是可以伪造的),接着 Alice 需要输入用户名和密码认证第三方;

但是 Alice 不这样做,没有输入用户名和密码,而是保存了这个 URL,而是让 Bob 以某种方式去访问这个URL,此时如果 Bob 用他的用户名密码登录到QQ授权服务器认证,此时,QQ 用他的身份产生了一个 授权码,重定向到知乎,此时相当于重复了一次请求到知乎,如果将cookie改为Alice自己的发回给知乎,那么 Alice 在客户端的账号就被认证成功,而进行认证的身份却是 Bob,能够获取Bob的信息;

如何防止

客户端应当基于当前需要认证的用户以某种方式产生一个值,保证其唯一性,保存到服务端中,这个唯一值由客户端发送给授权服务器,输入用户名密码授权后,授权服务器将这个值原封不动的进行返回给客户端,客户端比较授权服务器返回的值和自己保存的值,如果和原来发送给授权服务器的不一致,就会拒绝,不再获取 access_token

现在比如 Alice 保存了这个 URL,让 Bob 去登录,此时客户端会产生两个state, 分别是stateA,stateB,知乎用 Alice 的身份stateA发送给QQ,而Bob登录认证后,同样是stateA被返回到 知乎,知乎比较Bob本身的stateB和返回的state是否相同,此时 知乎 比较将会失败,拒绝下一步操作

state的唯一性防止了伪造攻击

时间: 06-16

安全系列之二:OAuth2.0协议的相关文章

基于OAuth2.0协议 第三方登录与数据同步验证设计

前段时间,公司跟别的公司签订合作伙伴,搞了一个第三方登录与数据共享同步,是基于OAuth2.0协议,现在空闲了,做一下笔记. 到github下载一个OAuth2.0的PHP类库(当然,你也可以自己写一个^-^,但个人觉得没必要造轮子),有写好Mysql与Mongodb的Demo,参考一下,然后嵌套自己的业务代码,下面是客户端与服务端的交互流程: +-----------+ +-----------+| | 带client_id的URL请求获取code | || | ---------------

深入理解OAuth2.0协议

1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店后,只需要将泊车钥匙交给服务生,停车的事情就由服务生去处理.与主钥匙相比,这种泊车钥匙的使用功能是受限制的:它只能启动发动机并让车行驶一段有限的距离,可以锁车,但无法打开后备箱,无法使用车内其他设备.这里就体现了一种简单的"开放授权"思想:通过一把泊车钥匙,车主便能将汽车的部分使用功能(如

Oauth2.0协议 http://www.php20.com/forum.php?mod=viewthread&amp;tid=28 (出处: 码农之家)

概要     OAuth2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0即完全废止了OAuth1.0. OAuth 2.0关注客户端开发者的简易性.要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户,要么允许第三方应用代表用户获得访问的权限.同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程.2012年10月,OAuth 2.0协议正式发布为RFC 6749 OAuth 1.0已经在IETF尘埃落定,编号是RFC5849这也标志着OAuth已经正

(转)帮你深入理解OAuth2.0协议

1. 引言 如果你开车去酒店赴宴,你经常会苦于找不到停车位而耽误很多时间.是否有好办法可以避免这个问题呢?有的,听说有一些豪车的车主就不担心这个问题.豪车一般配备两种钥匙:主钥匙和泊车钥匙.当你到酒店后,只需要将泊车钥匙交给服务生,停车的事情就由服务生去处理.与主钥匙相比,这种泊车钥匙的使用功能是受限制的:它只能启动发动机并让车行驶一段有限的距离,可以锁车,但无法打开后备箱,无法使用车内其他设备.这里就体现了一种简单的"开放授权"思想:通过一把泊车钥匙,车主便能将汽车的部分使用功能(如

OAuth2.0协议之新浪微博接口演示

新浪微博接口调用数据代码: <?php /** * @ Author : LiBo * @ Date : 2013-10-25 * @ File : weiboapi.php * * @ 说明:回调页面http://pressure.manyi.cc/weibo/ok.php中, * 仅做session保存code的值即可. **/ /** * 开启session,因为授权请求返回的code每次都会变化,而获取access_token是需要传递code的值, * 所以需要用session来存储c

PHP第三方登录—OAuth2.0协议

第2章 OAuth授权流程详解 

Oauth2.0(二):开放平台

上一节说到Oauth2.0 的交互模型.模型涉及到三方:资源拥有者.客户端.服务提供方.其中,服务提供方包含两个角色:鉴权服务器和资源服务器.鉴权服务器负责对用户进行认证,并授权给客户端权限.认证这一步好实现,无非就是验一下账号密码.但是授权这一步怎么做?我们看到在QQ的授权页面上,有”有道云笔记将获得以下权限“的字样以及权限信息.鉴权服务器需要知道请求授权的客户端的身份以及该客户端请求的权限.所以,需要在谈完合作之后,为每一个客户端预先分配一个 id,并给每个 id 对应一个名称以及权限信息.

Force.com微信开发系列(七)OAuth2.0网页授权

OAuth是一个开放协议,允许用户让第三方应用以安全且标准的方式获取该用户在某一网站上存储的私密资源(如用户个人信息.照片.视频.联系人列表),而无须将用户名和密码提供给第三方应用.本文将详细介绍OAuth协议以及在微信里的具体实现. OAuth2.0协议介绍 OAuth2.0是OAuth协议的下一版本,但不向后兼容OAuth 1.0. OAuth 2.0关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程. OAuth2.0允许用户提供一个令牌,而不是用户

OAuth2.0学习(5-4)新浪开放平台-微博API-使用OAuth2.0调用API

使用OAuth2.0调用API 使用OAuth2.0调用API接口有两种方式: 1. 直接使用参数,传递参数名为 access_token URL 1 https://api.weibo.com/2/statuses/public_timeline.json?access_token=abcd 2.在header里传递,形式为在header里添加 Authorization:OAuth2空格abcd,这里的abcd假定为Access Token的值,其它接口参数正常传递即可. 注:所有的微博开放