對抗假人 —— 前後端結合的 WAF

前言

之前介紹了一些前後端結合的中間人攻擊方案。由於 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

類似的對抗思路還有很多,以後有時間再分享。只有『技術』與『計謀』結合,才能在對抗中更勝一籌。

回到正題,對於這個系統來說,即使被破解也不會有太大的損失。只要換一套祕鑰算法和混淆方案,又可以繼續我們的防禦。自動化的部署,能讓我們的更新維護更簡單,爲持久對抗提供強有力的保障。

後記

我們把傳統的網絡攻防,轉換成逆向技術的對抗,讓系統涉及更多的領域。對於攻擊者來說,就需要掌握更多的技能點,從而提高入侵的門檻。

退一步,即使攻擊者能輕易破解我們的系統,那也無法立即應用於現有的安全工具,必須改造才能使用,同樣能大幅增加攻擊成本。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章