本文提取出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
下面是正文 工具
Open Authorization的缩写,即开放受权协议
OAuth 的受权使应用无需涉及另外一方应用的账号信息(如用户名与密码),只须要经过受权就能够另外一方应用的信息,保证了安全性,不会泄露用户名密码。
而整个流程要怎么作才能保证安全呢,该协议定义了规则。
更多的定义能够本身查看OAuth的维基百科
第一步:固然是上知乎官网登陆,点击QQ头像做为QQ登陆
图1
第二步:登陆QQ并受权,能够看到右边是QQ受权给知乎的内容,获取咱们的昵称,头像和性别等信息。输入用户名密码登陆,能够看到按钮显示的是登陆并受权,也就是是点击后就已经说明咱们赞成让知乎获取咱们的这些我的信息。
图2
由于我已经登陆了,因此直接点上面的QQ头像(头像就是多啦A梦)直接受权。
图3
第三步:登陆受权成功,能够在知乎的首页看到你的信息(还须要补充知乎的我的信息做为新用户注册)
图4
注意:有的网站受权,是先登陆后,进入另外一个页面而后再点击受权的。
PS:记住图的编号,后面分析用到
下面将进入正题,首先是上面涉及的几个角色,而后是协议流程等
前提:知乎要用QQ登陆,使用QQ的头像和昵称:
还有一个角色是资源全部者的用户代理(User Agent),通常就是咱们的Web浏览器,咱们须要浏览器做为代理才可以进行操做
本规范定义了四种许可类型——受权码、隐式许可、资源全部者密码凭据和客户端凭据——以及用于定义其余类型的可扩展性机制。其中受权码是咱们最经常使用的,所以单独讲受权码方式,其它类型详情能够自行下载RFC6749文档查看,下载地址在这里,搜索本身想要的文档,而后右键另存为下载便可
能够看到,受权码模式(authorization code)是功能最完整、流程最严密的受权模式。
+----------+ | 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文档
注意结合上面的协议流程看分析:
为何要分红两点呢?由于第一点咱们能够容易的抓取请求响应报文获得,而获取访问令牌的过程对资源全部者(咱们用户)是透明的,也就是说咱们不会看到访问令牌,只有知乎服务器获得了访问令牌;其实看不到也不该该让资源全部者看到,不然就不安全了,由于谁均可以用访问令牌到访问咱们的信息
那到底整个过程的细节是怎样的呢?我们开始分析请求响应包
这里使用Fiddler抓包工具,去除了某些头部,注意结合上面讲的内容;为了方便看报文,对其进行了换行处理;
重点关注:请求地址,响应状态值,Location;请求和响应过程当中的参数下一小节分析
请求报文:直接请求到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
受权响应
响应报文:重定向到Location上(redirect_url),也就是回到知乎,关键参数是code, state
HTTP/1.1 302 Moved Temporarily Location: https://www.zhihu.com/oauth/callback/qqconn? code=D38858BD4FE6058A48E461663ECB3CC3 &state=8821ffbf09c3ff9c401fe404aa7fcaf7
请求获取token,最后访问用户的头像,昵称等信息
这一步对咱们是透明的,咱们看不到,其实就是简单的调用API调用获取,关键参数有grant_type, client_id, client_secret, code, redirect_uri
访问令牌请求
下一小节有QQ API
受权服务器必须:
访问令牌响应
响应:关键参数有access_token, refresh_token
若是访问令牌请求是有效的且被受权,受权服务器颁发访问令牌以及可选的刷新令牌。若是请求客户端身份验证失败或无效,受权服务器返回错误响应。
QQ接入API
攻击方式
假设 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