标签:
本文提取出OAuth2.0规范RFC6749的主要内容,部分内容从文档复制出来,给大家讲讲第三方授权背后的故事。
先是举个知乎的QQ登录授权的例子,然后讲四种授权方式,两种令牌,接着是看看协议流程,分析知乎的QQ登录授权请求响应报文解释OAuth2.0协议,最后简单看看QQ提供第三方授权的API加深理解。
先打个预防针,在讲解四种授权,两种令牌时大家可能会有点不懂,但是跟随着协议流程走就懂了。
如果觉得排版不好,可以访问我的博客。TAT
blog.bensonlin.me
如果觉得写得不错,欢迎推荐,关注我和follow我的github(我的主页里)。
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://www.cnblogs.com/lzb1096101803/p/5592486.html