安全系列之二:OAuth2.0 开放受权协议

本文提取出OAuth2.0规范RFC6749的主要内容,部份内容从文档复制出来,给你们讲讲第三方受权背后的故事。html

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

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

 

若是以为排版很差,能够访问个人博客。TATgithub

http://blog.bensonlin.me/post/oauth2api

若是以为写得不错,欢迎推荐,关注我和follow个人github(blog.bensonlin.me上有显示)。浏览器

 

2016/06/18发现有人未经赞成复制个人文章到网站上,这里表示抗议,网站以下:安全

http://www.07net01.com/2016/06/1578637.html服务器

http://***/article/150992cookie

下面是正文 工具

 

什么是 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的惟一性防止了伪造攻击

 

转载请附上原地址:http://blog.bensonlin.me/blogs/oauth2

相关文章
相关标签/搜索