出处:http://www.cnblogs.com/neutra/archive/2012/07/26/2609300.htmlhtml
最近在作第三方接入的,初步定下使用OAuth2协议,花了些时间对OAuth2的受权方式作了些了解。前端
我还记得一两年前,跟一位同事聊起互联网时,当时我说过一个想法:算法
目前很多较为稀有的资源,不少都是论坛提供下载的,论坛提供的下载每每要求一个论坛账号,更有甚者,需回帖才可见,又或者下载须要消耗必定的虚拟货币,而这些货币能够用论坛活跃度而得到。假设如今我是一个普通用户,我要找某个资源。经过搜索引擎或者资料,我发如今某个论坛有这个资源下载,从其余地方得到这个资源代价比较高或者说根本就找不着。当我准备下载时,极可能就被提示需登陆后才可下载,随机被跳转到注册页面。后端
为了这个资源注册一个账号?我想,不管谁在99%的状况下都不乐意去注册一个只是用一次的账号,恰恰有些论坛就是为了某些缘由要求你必须提供一个账号。好吧,像我这样的人,固然是瞎填点信息注册个账号了事。至于注册了账号需不须要金币或者多少声望才能回帖下载之类的,这里就不唠叨了。这个过程的关键点是:我为了一个临时性的须要,注册了一个永久性无关痛痒的账号,这个账号使用一次以后,基本上失去价值了。有无数无聊的用户花了N多的时间在M多的论坛里注册了N*M个无用账号,这个过程除了对某些统计指标有利之外,对用户没有任何价值。浏览器
可不能够作一个平台,使任意用户能够在任意论坛注册一个账号,随后这个账号和密码自动登记到这个平台中做为公共账号,以后,其余用户再访问这个论坛时,就无需再次注册账号了,直接在这个平台上,自动地使用公共账号去作该作的事。这样,随着用户数的增长,最终能够达到一个比较理想的状况:大部分论坛的临时性操做,用户都不用再去注册了,也不用担忧本身的经常使用账号密码等信息泄漏的问题。尽管对于一些有“经济系统”的论坛(须要经过活跃度/发帖数/现金等有偿得到虚拟货币,存在消费行为),这个平台可能不适合,但即便需求只被解决了一半,也是个有价值的产品。安全
当时只是大概聊了下,彻底没有动手的打算,至今我还没发现相似的产品,不知是这个需求不够大众仍是什么。那时我也大概看了下OpenID,跟个人设想不同,OpenID是将一个用户在某个平台上的账号,公开给其余网站使用,固然公开的只是账号而不会包含密码。当时宣传的口号大概是这样的:“一次登陆,处处使用”。当时我只在豌豆网注册了一个OpenID试着玩玩,感受支持这个OpenID的资源网站太少了,那个账号做用不大。cookie
OAuth最近几年大行其道,很大程度得益于微博的推广。OAuth和OpenID是比较容易混淆的两个东西,比较“官方”的观点认为:OpenID设计目的是“身份校验”;OAuth的设计目的是“受权”。我也比较认同这个观点,但我以为这种说法自己也挺容易混淆,有位同事说“身份校验”自己就是对“用户资源”权限的授予,因此OAuth包含了OpenID的做用。session
在说明个人观点以前,不妨思考下,目前提供OAuth的网站有那些,他们的提供的服务是什么,为何他们大多都提供OAuth却鲜有说起OpenID?(我不是暗指腾讯啦)。网站
先看看OpenID,前面多少也讲过了,下面以豌豆网为例:搜索引擎
再来对比OAuth,用新浪微博为例吧:
一对比,区别就很明显了:OAuth和OpenID的区别主要是服务提供方是否提供有价值的资源。
做为一个拥有资源的服务提供方,固然但愿本身管理本身的用户信息。假如新浪微博支持其余网站的OpenID登陆,因为有很多的OpenID服务提供方,那么它须要如何管理本身的用户呢?例如,用户A经过网站X的OpenID登陆新浪微博,跟用户A经过网站Y的OpenID登陆新浪微博,最终的效果是一个账号仍是两个账号呢?若是用户A在新浪微博自己有一个账号的话,状况又更复杂了。要么全部账号都按新账号处理,要么提供多个账号关联功能。前一种方案简单易行,但产生了大量非活跃账号,用户体验也不见得好。后一种方案,想想都以为,维护是个灾难。因而,大多数的资源提供方都倾向与本身管理本身的用户信息,对于第三方的接入,开放一些受权给他们参与一些用户资源的访问就是了,因而便提供OAuth服务而不是提供OpenID接入,一些网站如腾讯还在 OAuth上提供了OpenID。写着写着,我本身都以为OpenID的“接入”和"服务"很拗口。好吧,OpenID的接入是说使用其余网站所验证的账号信息,OpenID的服务是指对外提供OpenID的身份校验服务。
把上面的状况循环循环再循环,最终,一方面,拥有有价值资源的网站,都作OAuth去了,他们在等待开发者和其余第三方网站的接入,壮大他们的平台;另外一方面,提供OpenID服务的小网站,几乎没有大网站的接入支持,对用户的吸引力愈来愈小,典型的恶性循环。而后,大部分网站的OAuth服务虽然基本是按照官网规范作接口,但很多细节都作了个性化。例如部分网站的expires_in单位是秒,部分是用分作单位的。部分网站支持state做为状态传递,部分又不支持。最终这些非标准的东西,会惹恼苦逼的开发者(为何我会很天然的想起IE?),相信不少开发者都会根据市场份额去选择几个流行的OAuth提供方进行兼容,其余的,见乔布斯去吧。而用户则会根据应用的数量去选择平台,又一个恶性循环。若是你的资源不够吸引开发者,就不会有人愿意为你的自定义标准买单。莫非这就是传说中的,合久必分分久必合?嗯,扯远了。
我并无贬OpenID褒OAuth的意思,只是以为在目前市场下,不太可能有大网站愿意放弃提供OAuth服务而使用OpenID接入外部账号。其实我对OpenID了解很少,写着写着,没想到居然写了一大坨,我真怀疑本身是否是话痨…… 有点晚,明晚继续,if有空的话。
OAuth2是从OAuth发展而来的,虽然不向下兼容,但了解OAuth能更好的理解OAuth2的一些改变。
OAuth里存在三个主要角色:用户、服务提供方和服务消费方。很多文档会把服务消费方说成是客户端,对于SP来讲,这个说法没什么问题,但我感受这个说放容易引发混淆,因此我这里仍是用服务消费方来描述。按流行的口号,服务提供方通常对外宣称本身是某某某开放平台,而服务消费方则是各类第三方应用。用户在平台上有一些已有资源,如好友关系,照片等。
几乎全部的OAuth平台都有相似的背景:他们原先积累了一大堆的真实用户,在互联网开放的趋势下,主动或被动的须要支持第三方应用的接入。第三方应用为了使其功能更加丰富完整,但愿从平台能获取甚至操做当前用户的资源。用户极可能不但愿第三方得知他原有的账号和密码,缘由很明显,安全考虑嘛。服务提供方也不但愿第三方直接使用用户的账号和密码登陆平台操做用户数据,为啥?不便于数据统计和维护嘛,但愿对 哪一个第三方操做哪一个用户数据 和 哪一个用户操做本身的数据 两种处理流程有所区别。第三方很无辜,常常大喊“我觉不会使用任何途径存储用户的账号!”。即便真有人相信这些誓言,但也很难确保第三方使用账号敏感数据时,不被第四方所捕获,因此,认真你就输了。
为了解决上面的问题,准确的说是让三种角色互相信任,OAuth由此而生。在没有第三方的状况下,服务提供方和用户能够认为是互相信任的,由于用户用域名来确保本身访问的是一个受信的站点;服务提供方则要求用户登陆,而且登陆会话能够控制。
应为第三方通常是不知名的,用户很难区分第三方合不合法,因此用户须要经过服务提供方来证明第三方,例如位于服务提供方的OAuth受权页面会简单的介绍该应用的简单介绍,正是这些介绍使得用户能够相信,该应用是一个合法登记的第三方。
为了让服务提供方信任第三方应用,第三方应用在必要时须要向服务提供方提供身份凭据。最简单的办法就是第三方开发者去服务提供方那去注册个账号,而后在须要时用这个账号来证实本身的身份。这种第三方应用的账号,下面统称应用账号。因为第三方的请求不会有人工的干预,因此应用账号的账号密码通常由服务提供商提供,方便服务提供方管理,安全系数也较高,由于服务提供方能够制定规则,使密码更难以伪造或猜想。
按理说,第三方应用除了到SP处申请一个应用账号外,也有其余办法证明本身的身份。
例如可使用HTTPS链接,让“第四方”去证实。OAuth2使用的就是HTTPS链接,但也仅仅是服务端认证,客户端并不作保证。估计一个方面的缘由是,应用的数量不少,通常都是中小规模开发商开发的,客户端也要认证的话,证书申请门槛较高,一个帐号密码能够解决的问题有必要去申请证书吗?另外一方面是,不少应用是没有服务端的,使用双向HTTPS认证无疑将这些应用拒之门外。
上面的方法是,用户经过服务提供方,去识别第三方是否合法。还有种方式是:服务提供方经过用户,去识别第三方是否合法。但OAuth里没有这种方式的体现,但OAuth2里有相似的方式,那就是提供用户的账号密码换取AccessToken,名字应该叫“资源全部者密码凭据”。若是第三方应用只是开发者自娱自乐的小应用,这种方式是最简单的。
通过上面的注册和受权流程,用户和服务提供方均可以确认第三方应用的身份了,那第三方如何确认服务提供方和用户的身份?
第三方应用怎么确认服务提供方的身份呢?很简单,域名就是服务提供方的惟一标识,只要DNS不被劫持的话。第三方应用根据服务提供方的返回内容确认用户身份,载体是操做令牌AccessToken,为了方便后面统称ATOK,在OAuth里,ATOK的有效期是从用户受权成功,到用户取消受权,对第三方来讲,几乎是永久的。至于用户受权以后取消受权,再受权的时候,两次ATOK是否同样,第三方可否处理好这种状况,OAuth里没有说起,看实现者的心情了。
把上面所说的综合在一块儿,能够获得一个OAuth的雏形版本:
第三方到服务提供方注册个应用账号,当须要操做用户在服务提供方处的数据时,提供应用账号密码申请受权,服务提供方将用户引导到受权页面,当受权成功时,服务提供方将对应该用户的ATOK发给应用,随后应用就使用这个ATOK来操做用户数据。
下面新浪微博OAuth的基本流程(其实各平台的流程都同样,贴这个是以为这张图比较好看):
从图中能够看到OAuth的流程比原先设想的雏形多了很多东西,这些多出来的有什么做用呢?
OAuth受权分四步:
第一步,应用向服务提供方申请请求令牌(Request Token),服务提供方验证经过后将令牌返回。这个步骤因为涉及到应用账号密码,在应用的服务端发起,因此这个步骤对用户透明。
第二步,应用使用请求令牌让浏览器重定向到服务提供方进行登陆验证和受权。服务提供方校验请求令牌,将第三方的资料显示给用户,提示用户选择赞成或拒绝这次受权。若是用户赞成受权,发放已受权令牌并将用户引导到当前应用的注册地址。这个步骤从重定向开始到引导回注册地址以前,应用方并不参与用户身份校验和受权过程,确保第三方不可得到用户的真实账号密码。
第三步,用已受权令牌向服务提供方换取ATOK。第三方应用需在服务端发起请求,用账号密码和上一步的令牌换取ATOK,这个步骤对用户而言也是透明的。若是前两步分别是让服务提供方认证应用和用户,那这步就是用户和服务提供方再次认证第三方应用。由于用户浏览器将第二步的结果重定向到第三步,除非用户DNS被劫持,不然就能确保重定向到的是合法的地址。曾经我很困惑在用户受权以后为什么不直接返回ATOK而须要再次换取,估计是出于对ATOK的安全考虑,用户浏览器一端存在太多的可能性让ATOK泄漏,最安全的办法仍是让第三方服务端来获取和保管ATOK。
第四步,用ATOK做为令牌访问受保护资源。不少时候,权限是有多种类别的。ATOK包含了某个用户对某个应用的受权凭据,准确的说,ATOK对应用户受权时所赋予的一系列权限的集合。因此在这一步,除了校验ATOK的合法性以外,服务提供方还需对该ATOK是否拥有足够的权限执行被保护操做进行判断。
在OAuth里,OAuth的相关请求都要作单次签名,目的是防止OAuth的请求被篡改和重放。签名固然是拿应用账号的密码来作签名,其实就是对HTTP请求中全部OAuth相关的参数都连在一块,使用密码计算某种哈希值做为签名。OAuth规范里描述了签名的规则,那是至关的繁琐、复杂,足以吓跑一大堆未经世事的开发者。随便找一个OAuth开放平台的API文档,我相信在OAuth受权流程有接近一半会在描述怎么产生签名构造一个合法的HTTP请求。有一对文字图片描述还不够,各开放平台几乎无一例外地提供各类开发语言下的SDK,为求尽可能下降技术门槛。即便如此,很多开发者依然以为,OAuth的签名过程实在是太复杂了,而这些复杂也没有带来预期的好处。
为了防止有攻击者伪造重定向地址骗取用户受权,服务提供方应对受权时的重定向地址进行验证。因此注册时,第三方应提供重定向地址。服务提供方能够直接对重定向地址进行等值判断,但这样的话就没办法让第三方在受权过程当中传递状态,只能借助Cookie/Session之类的方式了。服务提供方也能够判断重定向地址是否同一个域,这样的话应用方就能够在URI里传递少许状态。对于一些没有服务端的第三方Web应用,因为代码是公开的,将应用的账号密码存在页面里并不合适。OAuth则建议不使用重定向地址,让用户在受权后,把受权码人工输入到应用中进行下一步。记得有段时间FaWave也是这么添加新账号的。
OAuth曾爆了一个安全漏洞,攻击者利用此漏洞可骗取用户信任获取非法的受权。
这个网页有该漏洞的详细说明,流程以下:
简单的说,这个漏洞主要的关键是:
1. 部分服务提供方并未对重定向地址进行合法性判断,或者部分第三方的重定向地址会根据URI的参数再次重定向从而被攻击者利用;
2. RequestToken从未受权到已受权的状态转变时没有变化,从而为攻击者暴力访问回调地址骗取ATOK提供可能;
对于第一点,攻击者伪造重定向地址,便可骗得用户对可靠第三方的受权,得到ATOK
对于第二点,假如第一点不成立,那攻击者能够用第一步的请求令牌构造一个合法的重定向请求,并在用户受权以后、浏览器重定向到合法重定向地址以前,进行一样操做执行这个重定向操做,此时就看攻击者和正常受权流程就存在竞争关系。若是第三方先处理攻击者的请求,攻击者就得到了最终的ATOK。
为了解决上述安全漏洞,OAuth更新了1.0a版本,主要改变就是第一步增长对重定向地址的签名,和第二步与第三步之间增长一个随机校验码,使之与未受权的RequestToken有所区分。
目前大部分的平台都转到了OAuth2。OAuth2虽并不兼容OAuth1,但基本原理是同样的。
OAuth2对比OAuth1,主要改变有下面几点:
1. 取消繁琐的签名,所有改用HTTPS。
2. ATOK从原来的永久令牌变为临时令牌,增长RefreshToken
3. 取消获取RequestToken的步骤
4. 提供了多种场景的受权流程
OAuth原有的签名算法实在是太繁琐了,吓跑了很多开发者。对于服务提供方,也很很差实现,特别是单次签名的实现,因为服务提供方要确保每次由客户端生成的随机码不被重复利用,必须存储每次请求发来的随机码,不管是对存储仍是校验都是一个难题。一般的作法是,存储一段时间的随机码,这个时间需比RequestToken的过时时间要长。这样即便到时还有重放攻击,RequestToken也已经失效。
OAuth2取消了签名,改用HTTPS来加密,确保通讯内容不被第三方窃取。这个改变毫无疑问是下降了门槛,受权的流程被简化了。虽有少许人有异议,但OAuth2最大的异议是临时的ATOK。
因为第三方应用每每不重视ATOK的安全性,开发者为图方便常常把ATOK从后端发给前端页面或者存在cookie中。因为OAuth1中ATOK几乎是永久性的,即便发现ATOK被盗用,也只能让用户取消受权,这可能会形成一些其余的问题。OAuth2将ATOK改成临时令牌,当ATOK过时后,须要使用RefreshToken从新获取新的ATOK,让开发者郁闷的是,RefreshToken也不是永久性的,不一样的服务提供方有不一样的过时时间,相同的是,过时时间都不会太长,顶多也就几个月。
这个改变对不少第三方应用是个坑爹的改变,本来他们几乎都是拿ATOK做为OpenID来使用的(因此才有了各类ATOK被盗用的隐患),而到了OAuth2,ATOK已经不能惟一标识一个用户了,他们要多作不少的东西才能维持用户的身份,在使用ATOK访问用户资源时,步骤也是异常繁琐。
虽然临时ATOK这个改变很合理,但对开发者很不友好,从此会不会继续改变,能够拭目以待。我我的以为,这个问题实际上是另一个问题,那就是开发者对用户账号信息的安全意识太单薄,后面讲OAuth的问题时再详细讨论。
OAuth1流程比较复杂,尽管规范里有对多种场景的受权流程进行不一样的建议,但不少应用和开放平台最终都使用了同一种受权流程,结果产生了安全隐患(例如上面重定向地址的问题吗)。OAuth2描述了四种受权场景,为这些场景下的受权流程提供指导。我只简单说些要点和差别,详细的说明仍是看官方文档和各开放平台的文档稳妥些。