oauth受权协议的原理

 

http://oauth.net/2/ 协议的原文。原来是1.0版本,如今是2.0版本了php

 

https://ruby-china.org/topics/15396

https://blog.yorkxin.org/posts/2013/09/30/oauth2-1-introduction/
html

通俗解释:git

http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.htmlgithub

 

要解决的问题:算法

 

 

获取受权。每次登陆,都要让用户进行受权。数据库

 

 现实中的例子,只有用户赞成受权给妈妈网,腾讯才发放一个令牌给妈妈网,妈妈网凭借这个令牌去腾讯获取用户的信息。json

 

那么就意味着说,令牌的生成规则要跟用户和妈妈网的信息绑定关系。浏览器

 

奇怪,若是这个令牌被泄漏呢?别人也能够凭借这个令牌拿到信息啊。现实生活中,别人即使拿到你的令牌(票券),的确是能够去通行缓存

 

可是现实生活中发现了这个漏洞后,会增长一些安排判断,好比车票,别人就算偷到,捡到车票也不能去乘车,还要比对一下是否与身份证号码匹配。安全

 

除非你拿到对方的身份证了。这样把安全系数提升。发生的几率就会减小。就算你拿到对方的身份证,有时候还会看看你本人样子是否与身份证照片相差很大。

 

在咱们这一层,你在url中是能够看到key,没错。可是你得同时拿到密钥才行。须要密钥对数据进行签名的。签名失败是不容许访问的。

 

 

腾讯的微信是这样子:

一、用户受权后,则生成一个临时性的code返回给客户端

code如何生成的呢?参考了oauth2.0协议

 

该码与客户端ID和重定向URI,是一一对应关系。

 

客户端id。重定向的uri,是早就预约义好了。

 

请求腾讯去获取code的时候,会带两个关键性的参数:腾讯的appid(就是oauth2.0协议中的客户端id)、redirect_uri(腾讯要回跳回来的地址)

 

如今思考:为何要验证redirect_uri是否与后台填写的域名一致呢。其实这样能够增长安全性。

 

我只会重定向到指定的url去。这样会更加安全。不会重定向到攻击者指定的url去。

qq登陆的时候,还为了更加安全,作全路径判断了。之前只是同一个域名下便可了。后来为了安全。必须后台填写彻底相同的url地址。

 

好比后台配置必须是这样的完整url: www.abc.com/qqlogin/callback.php

 

是域名www.abc.com是不行,之前是能够的。

 

那么会彻底验证这个url是否一致。不然就拒绝掉。

 

这对于passport的参考意义:全部接入passport的子应用,我是否是能够限制回调地址呢?限制在指定域名下就能够。

 

目前来看,还不须要这样子作。没有遇到问题?

 

 

二、凭借appid和临时性的code去获取access_token

 

 

三、凭借access_token和用户的openid去获取用户的信息(昵称,头像等等)

 

 

通俗例子:

 

如今想要实现qq登陆。

一种办法是:让用户把对方的账号和密码发给a网站,让a网站去登陆qq。那这样就不安全了,由于密码不能泄漏给这些网站。

 

把账号和密码直接给a网站,a网站就能获取到qq的全部信息的权力了。这样子不安全。

 

如今明白缘由了,为何要设计一个用户的access_token,在每一个网站不一样。就是为了安全性。假设一个用户的access_token在a网站是同样的,在b网站也是同样的。

 

那么,泄漏了,就麻烦了。由于我能够获取用户的全部资料了。

 

这个access_token能够理解成令牌。

 

我在思考,我应该如何设计这种模式呢?

 

我能够画序列图,这样子清楚解释。

 

 

关键是这个access_token,这样子应用就不须要获取用户的密码了。彻底经过这个受权层来实现登陆。

 

我以为code 与access_token是创建了一个映射关系的。

 

access_token则是与用户的openid创建了映射关系的。

 

access_token  openid(根据appid和qq进行生成)

 

 

其实我在返回ticket的时候,彻底能够增长一个字段expire,表示过时时间。这样子他们本身能够根据去刷新本身的cookie时长?

 

子应用和passport系统登陆时间不一致,的确会致使一些用户体验很差。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

靠近你们的习惯。oauth2.0这样的模式去。

 

获取临时性的code。而后凭借code获取ticket(相似于access_token)。

 

每次请求都必需要带上passport授予的key在url中。

 

 

思考:qq,微信这些实现oauth2.0登陆的时候,为何除了带上screct还要带上appid呢?

 

微信登陆,只须要带上appid,就能够访问微信了。关于安全性,不过最终都要通过用户的受权:用户的微信账号必须是登陆状态。即使是登陆状态,也要通过用户受权访问。

 

一、跳转到微信的受权登陆页面去,不须要screct。由于这个须要用户受权才能操做。不涉及到安全性。之因此要传递一个appid在url中给微信,微信能够知道用户要登陆哪一个应用而已,方便作提醒"你正在准备登陆妈妈网"

 

二、经过code去获取access_token,须要screct的缘由是,这里涉及到安全性了。

 

 

为何要设计一个refresh token?

 

怕access_token过时。

 

为何要增长这个refresh token去延长access_token的有效期呢?

 

 

客户端:指的就是第三方应用程序。好比网站。

服务商:如何理解呢?通俗点理解呢。

资源全部者:指用户。这些资源是用户的,好比我的信息,保存的资料都是用户的。

 

 

 

 

 

 

state 用于保持请求和回调的状态,受权请求后原样带回给第三方。该参数可用于防止csrf攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加session进行校验

 

 

 

 

这个state指是能够网站本身设置的参数,qq那边只是原封不动的返回来。听说这样能够避免csrf攻击。

不太理解。可是能够模仿。oauth官网文档是推荐填写这个的。既然是为了不csrf攻击,伪造请求。

 

那么state的值就不要是一个固定的值了,由于能够伪造。因此要设置成一个动态变化的值。

好比能够:时间戳+随机数。时间戳是能够伪造的(用其余语言生成一个,时间只要同步就能够)。可是加上随机数。就很难肯定是哪一个随机数了。由于随机数每次都是变化的,对方就算模拟也很难模拟出刚好生成同一个随机数出来,它是在一个范围内变化的。

 

思考:为何单独只须要在浏览器重定向(好比腾讯回跳到本身网站)的时候,附加上state返回呢?

其余经过access_token获取用户信息,这些都是服务器之间的通讯。很难被截取到。

可是获取临时性code这一步,是在浏览器回跳的时候,别人也能够重定向这个地址,伪造请求。

 

如今要加上一个每次都变化的值会比较安全点。究竟是如何攻击的呢?

 

 

 

 

 

passport倒未必须要这样子,我以为passport调用方是本身的应用。不是外部应用。是本身公司的。是这样的吗?

 

 我如今能够设置一个时间戳,而后缓存在session中。qq会返回过来。若是返回来的值不同,则提示页面已过时。

 

 

 

 

 

 

 

 

 

 

 这是网页版登陆的正式文档:

https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&lang=zh_CN

 

弄错了,结果跑到公众账号平台去了:

http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code

 

难怪提示,必需要使用客户端打开。

 

实际上过程是:二维码。扫描后就能够进行登陆了。

 

 

 

我如今想理解一下,这个openid,unionid是根据什么生成的呢?

如何生成的呢?

 

同一个qq号,每一个应用id对应的openid会不一样。

 

容易把人给搞晕:access_token

openid之类的。

 

根据access_token才能访问。access_token存在有效期。附加上access_token和openid才能拿到指定用户的信息

 

 

 

 

 

 目前腾讯分配给咱们的appid是一个特殊的appid,因为是特殊性。在腾讯的后台查询不到,腾讯并无单独提供后台给咱们,直接修改回调地址。只能联系对方的技术人员修改

 

  关于当时的背景:理解下面知识点

 

   他们对一个用户(qq)的openid值是根据应用的appid生成的,也就是说:QQ号12348899,换一个appid,这个qq号对应的openid值就不一样了。

   这样子设计是为了安全考虑。不然不一样的应用(好比a公司和b公司的应用),只要知道一个qq号码,就能获取到它的openid去其余地方使用。或者保存到本身的数据库里面。

   如今目的要保证不同,腾讯每一个qq的openid值根据应用不一样,而不一样的。

 

  妈妈网当时为了解决这样的问题:

    因为32论坛的域名,都是不同的一级域名,好比www.gzmama.cn、www.cdmama.cn。根据腾讯的qq机制,那么同一个qq用户在这些应用对应的openid值就不同了。

    想实现32论坛的qq用户,表现得是同一个openid。根据上面对腾讯openid的介绍,腾讯原来的机制没法知足。因此咱们当时要求腾讯为咱们单独开设了一个appid。

    此appid是一个特殊的appid。把不少的应用合在一块儿。

 

 

 

 

 

 

 

 

赞成受权,实际上就是根据用户的登陆信息和appid生成一个code吗?这个code于这些信息是关联的。

 

回跳回来的时候,带这个code,凭借这个code能够获取access_token

 

 

我之前觉得,获取到access_token,获取到code会不安全。但实际上受权的模式已经避免密码泄漏的问题了。

 

对方如何才能获取到code,code只是一个桥梁,一个中间做用。用完一次就删除了。

 

关键是对方怎么攻击呢?

 

咱们的目的,就是要避免攻击者去获取用户的资源:照片,资料等信息。

 

必须经过用户临时受权,每受权一次才能进一步操做。

 

实际上能够直接返回access_token给客户端。可是不安全。必需要经过code来获取。

 

要隐藏。在服务器之间进行通讯,这样很难抓到包。

 

我只要拿到access_token,那么也是能够获取用户信息了。

 

请求的时候带scope参数,这样子受权服务器就知道这个应用打算申请什么权限,这样能够提醒用户:你将要受权进行干吗,你是否赞成。

 

 

在oauth2.0协议中,提供了好几种模式。其中一种模式是直接把access_token放到url中返回给客户端了。这种是简化模式。存在token被泄漏的风险。

 

 

 

 

 

 

 "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value"

要有访问令牌access_token。访问令牌有个过时时间。若是要延长,就要使用refresh_token来进行刷新。


access_token有效期是2个小时。refresh_token有效期是30天。


在qq中,Access_Token的有效期默认是3个月,过时后须要用户从新受权才能得到新的Access_Token。


这是php版本的 演示:
http://brentertainment.com/oauth2/lockdin/authorize?response_type=code&client_id=demoapp&redirect_uri=http%3A%2F%2Fbrentertainment.com%2Foauth2%2Fclient%2Freceive_authcode&state=6507ae4073f82d4a228eeef1a5af22d6#

https://github.com/bshaffer/oauth2-demo-php 这是官方提供的各个语言的demo


access_token与openid有什么区别呢?完成的意义有什么不同呢?


在oautho2.0协议原文中,只有access_token,并无openid的概念。因此openid只是在此基础上加的一个概念。







延长令牌,其实是从新生成一个令牌: 从新生成refresh_token和access_token,先判断这个refresh_token是否是合法就好了。



access_token和openid都要实时生成。

使用一种算法来生成。这种算法必须是可逆的。也就是根据access_token可以反解出uid出来。openid的值也是要同样的。

使用一个密钥来生成。

desc算法吗?


这篇文章比较好讲述了openid和access_token的区别

http://desert3.iteye.com/blog/1701626





关于access_token被盗用的问题思考

想一想现实生活中的例子,若是你捡到别人的火车票后,直接能够去乘车,之前是没有身份认证。我只认车票就放行。

这个动做就相似于,拿了access_token。

如今咱们的思路与车票增长验证是同样的思路,是增长验证,把门槛提升。

具体这样作:你拿到access_token还不够。还须要传递密钥来验证才行。

就算你能偷到access_token还不够,你还得知道密钥才行。

如今明白access_token的有效期不是安全的关键因素。短一点的确是比长更加安全。

安全的核心因素是什么呢?就是增长障碍物,门槛增长。

考虑到用code交换access_token是服务器之间的交互。code是容易被知道,可是密钥很难知道。token交换的时候是服务器之间的通讯了。

总结:思路就是增长多几道的验证门槛。



access_token准确的理解应该是这样:

是用户对第三方应用进行受权,受权能够在第三方应用进行登陆。好比妈妈网的用户,能够在挂号网站进行登陆。这须要用户进行受权才行。

受权过的用户会生成一个access_token,这个access_token要与应用id和用户id进行关联(对应关系存储起来)

这句话理解到了本质;OAuth能够把提供的Token,限制在一个网站特定时间段的的特定资源。





为何经过access_token就能直接去获取用户的信息呢?根本不须要传递密钥去。

腾讯和微博在这方面是同样的模式。怎么来理解呢?
难道是基于这样一个假设:access_token不能随便被拿到。须要门槛。因此若是你可以拿到,那就说明你是正常的用户。实际上,我以为若是是这样的理解,这种理解就是不够全面的。



把client_id和client_secret当作就是这个app访问受权中心的账号和密码,这么来理解会更加通俗点


这里解释了,为何access_token不要时间太长。

短时间token和长效的身份凭据 - 原先的OAuth,会发行一个 有效期很是长的token(典型的是一年有效期或者无有效期限制),在OAuth 2.0中,server将发行一个短有效期的access token和长生命期的refresh token。
这将容许客户端无需用户再次操做而获取一个新的access token,而且也限制了access token的有效期。

通俗点说,access_token是故意设置比较短的时间。而后增长一个拥有长有效期的refresh_token,来延长access_token的。




access_token的生成方式?

最好是不要在 token 字串附上这些信息,即便是 hash 过的也很差,由于这样子就有机会能够假造 token 。要把 token 字串视为一个参照,服务器用这个 token 字串去查到真正的受权内容
也就是说,access_token从安全角度来讲,仍是要用数据进行存储的。





Access Token 是一個字串,記載了特定的存取範圍 (scope) 、時效等等的資訊。
















两次的access_token:

8576C24EEA96E6AC8B035C375A47C922


8576C24EEA96E6AC8B035C375A47C922



两次的刷新token:

5FC5A99DA4774E7E3569B8BDC1170138

5FC5A99DA4774E7E3569B8BDC1170138



B03CD9A2AF5BA4CDCEA541366EFF995E

52C78B6D6F1D10979B1ED46B5F8709A2


每一次一个code。





经过openid获取用户信息的接口思考


想要获取用户的资料,经过传递openid来获取。可是还不够。若是知道openid被泄漏了。那么就能够获取用户资料,不安全了。

因此还要增长一个门槛,要传递一个access_token。先验证access_token的合法性。access_token带有失效期。是与client_id和user_id关联了。
若是access_token合法,就能查询到对应的client_id和user_id的信息。
那么user_id知道了就方便查询哪一个用户信息了。而且,咱们还要验证openid的合法性。openid是根据user_id和client_id换成必定算法生成出来的。
因此查询出的client_id和user_id,就能用算法算出openid,假设是openid_b,与传递过来的openid_a对比,是否一致。

不一致,就要报错:openid错误。

总共两个错误:access_token错误和openid错误。

思考:发现要研究,就把一些东西给研究透彻。而后本身可以回答一些关键性的疑惑。抛出一些问题来,才能解释掉。好比oauth,不用输入账号和密码就能够了。觉得有个access_token就能够。那岂不是没输入账号和密码就能拿到access_token。
refresh_token完成的意义有什么不同呢?
相关文章
相关标签/搜索