想当然的if...else引发的安全漏洞值多少钱?Github说:25000美元

发表于:2019-11-11 09:41

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:佚名    来源:纸飞机技术拆解局

  今天在网上闲逛,看到了Teddy Katz所写的关于他是如何攻破Github OAuth流程的帖子,觉得很有意思,应该说,其中所包含的基本知识,其实并不复杂,甚至应该说,对于每个从事这个行业的人来说,都是耳熟能详的。
  但偏偏的,很多人都会有意识无意识的忽略它们,Github则为此付出了高达 $ 25,000 ,约合人民币 十五万多 的代价,教训不可以说不深刻。
  
  因此,决心将之记录下来。
  起因
  事情的起因并不复杂,在今年夏天,Teddy Katz突发兴趣,决定利用他的业余时间,研究下GitHub Enterprise,是否存在有安全漏洞
  一切都表现的很好,直到他意外的发现了……
  Github的OAuth流程
  假设有一个第三方应用程序,比如说,Foo App,想要访问用户存储在GitHub数据,OAuth流程应该怎么走?这方面,Github和其他提供第三方登陆功能的大型软件没什么区别,总体上,其实就是三步:
  首先,Foo App会通过查询字符串(Query String),将一堆对Github来说有效的应用程序信息,比如向client_id、redirect_uri、scope等,发送到Github的认证接口上。
  然后,Github则会在扒拉扒拉处理了一阵后(包括实现未登陆的用户的登陆流程),向用户显示一个授权确定的页面:
  
  接着,当用户单击页面上的“Authorize …”按钮后,该页面会通过POST模式向Github发送包含CSRF令牌在内的另一些数据,Github继续扒拉扒拉的一通处理,然后就将包含有授权码(code)的信息,重定向发送到Foo App所提供的接口地址上。
  最后,在Foo App的接口中,凭借着这一授权码,Foo App继续的和Github的令牌申请接口通讯,以最终获得可在后续一段时间内使用的访问码(Access Token),凭借该访问码,就可以持续的通过Github的各种接口,来获取用户的信息了。
  一切都“几乎”是完美的!
  问题出在哪儿了?
  那么,Teddy Katz又发现了什么呢?其实,只有一个事实,那就是,Teddy Katz先生发现:
  从请求认证,到用户单击“Authorize …”,Github所使用的,都是一个URL地址,即:
  https://github.com/login/oauth/authorize
  于是,Teddy Katz就猜想,在这一事实的背后,可能会存在着一个简单的处理逻辑,即:
  
  这个业务逻辑有什么问题吗?
  别忘了HEAD
  这样处理当然有问题!起码在Teddy Katz看来,因为,我们大多数人,都有意无意的忽略了:
  HEAD的存在
  是啊,自从最初创建HTTP以来,HTTP HEAD方法就已经存在了,但是却并没有得到太多的使用。
  当服务器接收到HEAD请求时,预期的语义,在很多语言和框架下,则变成了
  假装这就是一个GET请求,但仅仅是要求服务器返回响应头,而不需要返回响应主体”
  这样,我们就能在,比如客户端决定是否需要开始下载文件前,通过HEAD的Content-Length,先来检查下文件的大小,从而做一些必要的准备,……
  好吧,但这里的一个重点就是:
  假装不代表真实,假装是一个返回部分信息的GET请求,不表示HEAD就是GET,不表示你明明发送的是HEAD,但检测request.get时,系统就会自动但返回true!
  不返回true,返回什么?
  当然就是false喽~~~
  Teddy Katz的魔法
  Teddy Katz就是这样猜想的。
  首先,假如刚好现在在一次浏览器的会话过程中,某个用户,已经登陆过Github,而且还是恰好的,他在浏览器中,设置启用了第三方Cookie(实际上根本不用设置,因为这是大部分浏览器的默认设置)。
  而因为Github广泛的采用了Ruby on Rails来开发,对于Rails来说,如果这个时候,可以实现通过HEAD模式来向 https://github.com/login/oauth/authorize 发起请求,那么:
  一方面,路由器会将这视为是一次普通的GET请求,而因为是GET请求,所以就不会对其进行相应的CSRF令牌验证,而是会直接调用对应的控制器代码。
  另一方面,对于相应的控制器代码而言,此时,则会识别出,这不是一次GET请求,因此,就应该和用户单击了“Authorize …”按钮后,所进行的操作一样,调用对应的POST部分代码,并最终像操作端口发送相应的code。
  如果在Github的认证流程中,对从code到access code这个过程,没有“特殊”的控制的话,那么……
  这就等于是说:
  在没有任何用户确认的情况下,仅仅是因为该用户在一次浏览器会话中,“一不小心”的访问了某个“不属于”已使用Github进行登陆的网站的“第三方”网页,用户的Github数据,就完整的泄露给了第三方网站!
  很快的,Teddy Katz的猜想很快得到了他的证实,他将这一发现报告给了GitHub’s bug bounty program,很快,其实仅仅使用了三个小时多,Github就修复了这个漏洞,并因此向Teddy Katz支付了$ 25,000。
  后记
  这当然是一起事故,但事故的起因,其实却非常的简单,仅仅是因为那个讨厌的if…eles,仅仅是因为遗忘了除了GET/POST,其实就HTTP协议本身所支持的,至少还有HEAD/PUT/DELETE等等方法,尤其是HEAD,对于开发而言,有时候多多回到最基本的知识点,并从这里出发,去检查代码是否可能存在相应的逻辑上的漏洞,其实有时候是一个非常有效的行为。
  但还是那句话:
  谁让我们只是人呢?

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号