繼續趣事分享。
上回聊到了大學裡用一根網線發起攻擊,今天接著往後講。
不過這次講的正好相反 —— 不是攻擊,而是防禦。一個奇葩防火牆的開發經歷。
第二學期大家都帶了電腦,於是可以用更高階的方法斷網了。但裝置先進反而沒有了 GEEK 的感覺。於是,決定做些其他更有意義的事。
一天,幾個好友在吐槽,他們的遊戲伺服器又被打垮了,接著討論起各種防護方案。
在過去,每當聽到防火牆軟體時,就覺得毫無卵用。巨大的流量一來,頻寬都堵死了,軟體又有何用。
不過,大家仍對其寄以厚望。而且還有不少廠商在做,看來,效果總是有一點的。
討論討論著,不免又有些蠢蠢欲動。要不,做個防火牆吧,做一個思路完全不同的!
當然,這不是第一次嘗試。
初學那會,沒有固定的目標。每看見一個小 demo,就想搞個大程式。比如看了 DirectX 就有做遊戲的衝動,但不出幾天就不了了之。
有段時間對驅動程式產生了興趣,琢磨起 Windows DDK 裡的 demo。當看見 NDIS 中介軟體這玩意時,頓時起了精神。這不就是一個最底層的包過濾器嗎,用來做防火牆,效能自然是極好的。
於是心血來潮,照著其中的樣例,改造出一個最簡單的 IP 過濾防火牆。為了凸顯高效能,硬著頭皮看了本資料結構,依樣畫葫蘆寫了個雜湊表,來更快查詢。
然而快歸快,沒有實際用途,不過是個玩具罷了。
現實中的防火牆,也不可能這麼簡單的邏輯。肯定還需更高層的協議分析,複雜的策略判斷,大量的資料積累。。。當然還少不了無數次的藍屏除錯。
想到這,立馬就沒有了繼續。
然而這一次,決定不再糾結技術層面,而是做一個“另類”的 —— 用最簡單的技術,加上巧妙的想法,配合一些獨門絕技,來獲得出其不意的效果。
考慮到傳統的開發人員,對系統、網路都已經非常熟悉,和他們比拼這些,就毫無優勢了。
而當時的我,點滿了一個和安全毫不相干的技能 —— 網頁尾本特效,以及一堆“前端黑魔法”。
但是。。。這。。和網路防禦。。。有什麼關係?
沒有半點關係~~ 想多了。還是考慮正經的吧。
首先想到的,是改造服務端。
畢竟這是“開源”的,肯定能通過修改程式,來加強那脆弱的網路系統。
然而,當看到那密密麻麻的程式碼、從未用過的語言、完全不熟的偵錯程式,興致蕩然無存。
沒興趣就沒想法,果斷放棄。
既然如此,那就從客戶端試試。
這一次,抱著探索的心情,開啟程式,細細揣摩起來。
正當毫無頭緒時,突然傳來親切的嚓嚓聲 —— 敏感的神經怎能放過,這不是 ie 的專屬聲音嗎。
這才猛然意識到,登入器中內嵌的,不正是一個大大的網頁!
有網頁,不就可以執行指令碼了!
從沒想到,居然打起了這個內嵌框的主意~~ 但總算把指令碼扯到一起了。
越想越興奮。現有的防火牆,幾乎都是純服務端的資料分析,能讓客戶端參與的,應該還很少吧。
“只要在登入器的網頁裡引一個指令碼,就能…”
大家聽了,表示可以接受。
有指令碼,就可以盡情發揮了。
我們必須讓使用者執行指令碼,才能連上游戲伺服器;沒執行過指令碼的 IP,就一律阻攔。
於是開始構思、整理:
- 當指令碼執行時,傳送一個請求給 “授權伺服器”
- “授權伺服器”驗證引數之後,將使用者 IP 通知給“遊戲伺服器”上的防火牆,新增到白名單
- “遊戲伺服器”只允許白名單的 IP 通過(“授權伺服器”預設在白名單)
正常使用者,這並沒影響;但攻擊器不會執行指令碼,也就無法進入白名單 —— 無論傳送什麼資料包,都會被攔截。
這樣,防火牆的策略,也變得極其簡單:僅僅判斷資料包的 IP 是否在白名單裡。
於是,之前那個簡陋的 demo 驅動又被翻了出來。因為功能單一,保證了穩定性。而且是在網路卡鏈路層上攔截,所以有超高的效能。
到此,一個 JavaScript 參與的網路防火牆原型誕生了!
也許你會說,這只是轉移了風險而已。把遊戲伺服器的風險,轉移到了網站上。要是網站被打垮,同樣無法進遊戲。
的確如此。不過相比普通的網路程式,Web 有更多成熟的防禦方案,甚至用現成的 CDN,就可以緩解。
因此將普通的 C/S 網路防禦,掛靠在了更穩定的 B/S 之上,就無需再造輪子了,節省大量成本。
當然這只是基本雛形。實際應用,還有不少需要考慮的地方。
例如,白名單不能無限增加,得有過期時間;客戶端的指令碼,也不能只執行一次,得定期觸發啟用。
….
不過,由於無需考慮相容性問題,使得開發十分順利。伺服器都是 Win2003;網頁執行在 WebBrowser 控制元件裡,都是 ie67 的核心。
幾天後功能完成。接著做了個簡單的介面程式,將方案進行包裝,就開始試用了。
上線後,效果很理想!任何與玩家無關的流量,都進行了攔截。輕鬆抵擋住了各種 CC 攻擊!
不過,攻擊者也絕不會罷休。
況且,前端的一切都是公開的,這個祕密早晚會被發現。
對抗 v1
平靜了幾個月後,一大波殭屍又來了。
日誌顯示,短時間內白名單進了大量 IP,這絕不是正常使用者的。
顯然,已有人發現了這個祕密!
事實上,第一版做的非常簡單,甚至連指令碼都沒混淆。
他們把指令碼邏輯,移植到了攻擊器裡。這樣不訪問網頁,也能變成合法使用者了。
至於他們是如何發現的,無從得知。但腦補發現後的心情,一定是這樣的:臥槽,原來是在這裡,居然這麼猥瑣~~~~
當然,這是意料之中的事。
新版本早已準備就緒,“前端黑魔法” 也躍躍欲試,決定進行反擊。
這次,將指令碼進行了加密。
不,不是網上流傳的那種加密,而是特殊構造的。雖然看起來差不多:整個程式,套在一個 eval 之中。
懂點 JS 的都知道,把 eval 換成 console.log 之類的,程式碼就原形畢現了。相信 99% 的人會這麼做。
於是,利用大家這個心理,在程式碼中埋下一陷阱:如果只解密,不 eval,就會出現意外的後果。
1 2 3 4 5 6 7 8 9 10 |
eval( (function() { ... T = setTimeout(die, 1) ... code += 'clearTimeout(T)' ... return code })() ) |
在解密過程中,偷偷開啟一個定時器:1 毫秒後,進入自殺模式 —— 死迴圈記憶體申請!
正常情況下,這並不會觸發 —— 因為隨後 eval 的程式碼裡,會解除這個定時器;但如果把 eval 換成其他的,就無法執行解除了 —— 炸彈觸發!
當時的主流記憶體還是 1~2G,這會瞬間被吞光,卡到硬碟吱吱作響。
為滿足好奇心,想看看有多少人栽進去,因此在死迴圈之前,還加了日誌上報的功能。
那段時間,正好在琢磨一個簡訊介面。於是,這日誌就成了測試內容。
每當有人試圖破解指令碼時,手機就立即收到了訊息,體驗了回“盡在掌控中”的感覺:)
當然,就這樣結束了嗎?
不,還早著呢。