标签:
http://oauth.net/2/ 协议的原文。原来是1.0版本,现在是2.0版本了
https://ruby-china.org/topics/15396
https://blog.yorkxin.org/posts/2013/09/30/oauth2-1-introduction/
通俗解释:
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
要解决的问题:
获取授权。每次登录,都要让用户进行授权。
现实中的例子,只有用户同意授权给妈妈网,腾讯才发放一个令牌给妈妈网,妈妈网凭借这个令牌去腾讯获取用户的信息。
那么就意味着说,令牌的生成规则要跟用户和妈妈网的信息绑定关系。
奇怪,如果这个令牌被泄漏呢?别人也可以凭借这个令牌拿到信息啊。现实生活中,别人即便拿到你的令牌(票券),的确是可以去通行。
但是现实生活中发现了这个漏洞后,会增加一些安排判断,比如车票,别人就算偷到,捡到车票也不能去乘车,还要比对一下是否与身份证号码匹配。
除非你拿到对方的身份证了。这样把安全系数提高。发生的概率就会减少。就算你拿到对方的身份证,有时候还会看看你本人样子是否与身份证照片相差很大。
在我们这一层,你在url中是可以看到key,没错。但是你得同时拿到密钥才行。需要密钥对数据进行签名的。签名失败是不允许访问的。
腾讯的微信是这样子:
1、用户授权后,则生成一个临时性的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的子应用,我是不是可以限制回调地址呢?限制在指定域名下就可以。
目前来看,还不需要这样子做。没有遇到问题?
2、凭借appid和临时性的code去获取access_token
3、凭借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,就可以访问微信了。关于安全性,不过最终都要经过用户的授权:用户的微信帐号必须是登录状态。即便是登录状态,也要经过用户授权访问。
1、跳转到微信的授权登录页面去,不需要screct。因为这个需要用户授权才能操作。不涉及到安全性。之所以要传递一个appid在url中给微信,微信可以知道用户要登录哪个应用而已,方便做提醒"你正在准备登录妈妈网"
2、通过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) 、時效等等的資訊。
![技术分享](data:image/png;base64,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)
两次的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。
标签:
原文地址:http://www.cnblogs.com/ldms/p/5241489.html