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