之前介紹了一些前后端結合的中間人攻擊方案。由于Web 程序的特殊性,前端腳本的參與能大幅彌補后端的不足,從而達到傳統難以實現的效果。
攻防本為一體,既然能用于攻擊,類似的思路同樣也可用于防御。如果將前端技術結合到傳統的WAF中,又能有如何的改進?
機器人的威脅
注:作者原文中用詞為“假人”,小編改為機器人
簡單易用,是 Web 服務最大的優勢。然而,這也是個致命的弱點。
這種格式簡單、標準一致的特征,使得攻擊者能利用現有的安全工具,進行大規模、通用化的探測和入侵。甚至無需了解其中的原理。
試想一下,如果某個網站使用私有的二進制協議,那么即使存在漏洞,也得先考慮通信問題。若是寄托于現成的安全工具,那就更舉步維艱了。然而現實中是不存在的。通用性和低成本,始終是首要因素。
要模仿這種簡單的協議易如反掌。于是,各種需要重復勞動的地方,都能見到機器人的身影。對于需要反復測試的安全領域,更是必不可缺。
傳統 WAF
傳統 WAF 大多關注于信息監控,記錄攔截各種異常的輸入輸出。對于用戶的真假鑒別,并非是其重點。
然而現實中,大多異常的請求,都不是正常用戶發起的。有誰會那么閑,把各種帳號一次又一次輸入測試撞庫?或者反反復復的在瀏覽器里嘗試內網探測?沒有工具的協助,安全檢測將是無比的折磨。
遺憾的是,WAF 很難從表面上識別用戶的真假,只能對其一視同仁。通過之后更詳細的規則進行綜合分析,才能做出判定。因此,這樣的決策似乎有些『有理無據』。
有理。例如正常用戶每秒只有幾個請求,但攻擊者開了漏洞掃描工具,短時間內產生了上百請求,這顯然不符合常理。
無據。雖然判定一個用戶并不難,但要拿出確鑿的證據,卻不容易。
這種模糊的規則難免會有一些的誤差。若是內網里有人對網站進行入侵探測,很可能導致正常用戶也被屏蔽;或者攻擊者放慢掃描速度,興許又能躲過監視。
當然,一套好的規則和模型能讓攔截更精準,不過這需要大量的分析和積累。對于 Web 這類特殊群體,我們能否另辟蹊徑,尋找一種既簡單又靠譜的方案?
在之前講解的流量劫持系列中也曾提到,后端分析是十分被動的。好在它掌控著流量大權,而 Web 這種特殊流量,同時具備可執行能力。因此可化守為攻,開辟一條全新的作戰方案。
所以,我們得借助前端技術,來實現最終目標 ——做一個有理有據的規則系統。
但一個令人信服的證據不會無中生有,必須人為約定和創造,并在適當的時候將其帶上,做到真正的『理據服』。
現有解決方案
在開始構思的我們的『前后端 WAF』之前,有必要提一下現有的解決方案。
每當遇到這種禁止改包重放的場合,安全工程師們總能不假思索的給出解決方案。例如讓頁面產生個唯一的隨機數和時間戳,加密后讓后端去驗證。
如果僅僅是為了解決個例,這樣倒也無可厚非。然而現實中,這樣的需求并不少見。如果要讓每個業務都去現實這樣的方案,將會極大增加前后端開發維護成本。
所以,把一些具體的方案拋給開發者,是很不合理的。對于開發者來說,理應投入全部精力在產品業務的開發上;與其不相關的事,都應交給適配層,讓開發者無需了解任何細節,自動幫其實現。
于是,我們需要一個前后端相輔相成的切面系統,在其中透明解決這些瑣碎的問題。這樣才可大規模部署,以及后期統一更新和維護。
前后端結合WAF
提到切面,Web『中間件』自然是我們的切入點。和過去的『中間人』劫持類似,我們在頁面中注入一段腳本,以開啟前端功能。
派出了位于前線的哨兵,就能提供更詳細的情報,這在過去是難以實現的。如今前端技術日新月異,利用這些優勢,我們開始構思一個全新的系統。
前面提到,如果能在發起請求時,提供一個證據來證明自己不是外人,那樣后端就會好辦的多 ——不懂規矩的機器人,自然會立即暴露破綻。
因此我們給頁面 IO 做一層切面:在請求發出前一刻,帶上一個蘊含各種私密信息的暗號,供后端驗證。
借助之前《SSLStrip 的未來 ——HTTPS 前端劫持》中使用的技術,稍作修改即可實現前端層面的請求攔截。
如今我們目的更簡單,只是攜帶一個額外參數而已,因此對于同站的請求,甚至無需修改目標 URL,將參數儲存在 cookie 即可自動帶入請求。
于是,開發者無需任何修改,就能獲得更安全的防御。
秘鑰策略
在秘鑰中,我們可儲存各種環境的上下文,例如:
只能用一次的隨機數,防止請求重放。
表單數據的校驗值,防止中途被改包。
當前時間戳,讓后端更精準的掌握發包間隔。
瀏覽器 BOM 特征,校驗是否和 UserAgent 描述的瀏覽器相符合。
......
最終通過私有算法,將其編碼成一個暗號秘鑰。
當然,這個秘鑰并不要求每次都嚴格驗證。事實上首次訪問,就是沒有秘鑰的;或者在鉤子之外的網絡請求,例如圖片等資源文件,無法保證每次都有唯一的秘鑰。
在 Web 富應用時代,『AJAX』和『JSONP』承載了絕大多數的接口請求,因此我們需嚴格防御。而普通的靜態資源風險則小得多,可以更寬松一些。
后期對抗
不過,類似的系統曾經也有過嘗試,但都是備受爭議的。原因很簡單,秘鑰是在前端生成的,其中的秘密查看頁面源碼即可獲得。一旦算法被解開,機器人也能冒充真實用戶,整個系統就失去了意義。
這也是為什么把『前端中間件』標注成黑色背景 ——我們需要將前端腳本高度混淆,讓攻擊者難以在短期內破解其中的算法。
于是,我們可以把網絡上的對抗,轉換成逆向技術的比拼了。讓攻擊者需要具備更多的技能,從而提高入侵門檻。
黑盒對抗
即使無法破解,攻擊者也能想盡辦法,將其當做黑盒來使用。我們舉幾個能預測的情況,進行攻防模擬。
No.1
攻擊者可完全無視加密細節,直接把機器人的請求轉到頁面進行代理,因此看起來就像是正常業務發起的。
對于這樣的情況,很難有絕對的防御措施。但可以用簡單的策略:限制請求頻率,從而降低攻擊速度。
我們設定一個相對寬松的請求數閾值,如果一定時間里達到上限了,就讓前端鉤子 Pending 住請求,稍做休息再發出。并且堆積的越多,就讓它推延更久。
如果正常用戶短時間里操作太快,導致請求超標,那么懲罰幾秒也情有可原(再說點的太快本來就會卡);但請求數持續居高不下的,那就很可疑了,是不是該好好休息下呢?
我們把請求數記錄到全局存儲里,在多個頁面間共享,防止多開慢刷;并且頁面關了仍然保留,下次回來繼續懲罰,避免反復刷新頁面清零。
No.2
即便如此,攻擊者仍能想出一些規避方法。例如開上幾個不同的瀏覽器、甚至虛擬機,作為完全隔離的環境,單獨慢慢刷。
對付這樣的機器人,就得用一個靠譜的識別手段:用戶行為分析。
正常的用戶瀏覽頁面,總是伴隨著鼠標滾輪、移動、點擊、觸屏等事件。而且網絡請求的發起,大多通過這些事件的驅動。若頁面一動不動,卻在不斷的發請求,那很有可能就是開掛的。
甚至還可以考慮把采集到的行為數據,通過密鑰提交到后端進行分析,建立更詳細的行為模型。
No.3
當然秘密總是會被發現的。行為采集這個門檻也難不倒攻擊者,如今能模擬用戶行為的機器人也不在少數,它們能逼真的模仿出各種事件,而我們也只能初略的分析。
不過能把攻擊者的門檻提高到這一步,我們的目的也達到了 ——我們并非要 100% 阻止機器人,而是通過對抗減少機器人。
End
在黑盒對抗下,由于攻擊者 不了解實情,只能見招『猜』招,很是被動。我們可以不時更新下腳本,調整策略,或者添加一些巧妙的思路,不斷折磨攻擊者。
對于攻擊者,顯然不甘長久在黑盒中對抗,會想方設法破解腳本。
逆向對抗
好在相比傳統語言,JavaScript 流行起來的時間還很短,成熟的逆向工具少之又少。而且運行于瀏覽器,又會牽扯到各種 DOM 與 BOM,因此還得了解不少的前端知識。
做一個好的混淆器,需要不少理論知識。不過不必搞的那樣先進 ——我們只需比攻擊者想的更遠就可以了。
在實際對抗中,無需太過糾結『技術』層面,更多的是需要『計謀』。有些東西其實原理很簡單,但就是想不到。這里就不詳細討論混淆技術了,分享幾個非技術層面對抗的案例。
脫殼迷惑
真正的腳本混淆器,應該是打亂原先的代碼結構,并且加入各種多余語句,以增加調試復雜度。
不過目前有相當多的混淆器,只是加個殼而已 ——把原先的代碼進行加密,運行時解密再 eval 執行。要解開這種『混淆』毫不費力,把 eval 替換成 alert 就成原形畢露,相信大家都嘗試過。
當然,我們也可以利用人們一些天真的想法,進行真假迷惑。
我們顯然不會『加殼』原始代碼,但可以準備一套偽代碼,假裝先解密再 eval。這套假代碼看上去和真的一樣,但里面的功能并不會觸發,僅僅用以迷惑而已,把攻擊者引到錯誤的方向上,從而浪費其時間。
而真正的代碼,則夾雜在解密的區域,在脫殼之前已經開始運行了。
在解密偽代碼的時候,還可以往其中插入大量無用的內容。例如眼花繚亂的特殊符號、成千上萬的續行符,阻礙正常閱讀。
盡管這不能解決根本問題,但能消耗攻擊者的精力,這就是非技術對抗。
蜜罐釣魚
既然想逆向,那總得先大致看一下腳本。在眼花繚亂的代碼里,一段可讀文本,就像是萬木叢中一點紅。利用它吸引攻擊者的眼球,從而上鉤。
例如,我們在代碼開頭的某個字符串里,寫一段『… compressed by xxxtool』。攻擊者看到這段文字,必然會好奇 xxxtool 是什么工具,于是就去網上搜索。
我們預先制作一個簡單的網頁,提供在線 JavaScript 的加密和解密。名字就叫 xxxtool,一個非常特殊的名字。我們從不推廣這個頁面,正常情況下根本不會有人來訪問。
當攻擊者搜到這個網站,自然會進來看看。發現還提供在線解密,以為找到了解藥,立即將代碼粘進來試試。
落入了我們的蜜罐,就免不了被我們忽悠了。如果是一般的腳本,就顯示普通工具的結果;一旦發現是在解密自己的代碼,趕緊拿出預先準備的那套偽代碼,讓攻擊者誤以為成功解開了。
同時,只要攻擊者一進入我們的網頁,就立即上報給云端,能及時了解有誰在研究我們的腳本。甚至還可以記錄下訪客的 IP,通知給 WAF 封殺一段時間。
當然,也未必要那么復雜。我們可以在一個永遠到不了的條件分支里,請求一個特殊頁面;如果某天發現這個頁面有訪問量了,顯然是有好奇的人在嘗試破解。
End
類似的對抗思路還有很多,以后有時間再分享。只有『技術』與『計謀』結合,才能在對抗中更勝一籌。
回到正題,對于這個系統來說,即使被破解也不會有太大的損失。只要換一套秘鑰算法和混淆方案,又可以繼續我們的防御。自動化的部署,能讓我們的更新維護更簡單,為持久對抗提供強有力的保障。
后記
跨越一個領域,可以讓思維空間更加廣闊,更多可選的解決方案。
對于攻擊者來說,需要掌握更多的技能點,從而提高入侵的門檻。