自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

針對XSS漏洞的前端防火墻:可疑模塊攔截

安全 應(yīng)用安全
由于是在前端防護,策略配置都能在源代碼里找到,因此很快就能試出破解方案。并且攻擊者可以屏蔽日志接口,在自己電腦上永不發(fā)出報警信息,保證測試時不會被發(fā)現(xiàn)。

上一篇介紹的系統(tǒng),雖然能防御簡單的內(nèi)聯(lián)XSS 代碼,但想繞過還是很容易的。

由于是在前端防護,策略配置都能在源代碼里找到,因此很快就能試出破解方案。并且攻擊者可以屏蔽日志接口,在自己電腦上永不發(fā)出報警信息,保證測試時不會被發(fā)現(xiàn)。

昨天提到最簡單并且最常見的XSS代碼,就是加載站外的一個腳本文件。對于這種情況,關(guān)鍵字掃描就無能為力了,因為代碼可以混淆的千變?nèi)f化,我們看不出任何異常,只能將其放行。

因此,我們還需增加一套可疑模塊跟蹤系統(tǒng)。

被動掃描

和之前說的一樣,最簡單的辦法仍是遍歷掃描。我們可以定時分析頁面里的腳本元素,發(fā)現(xiàn)有站外地址的腳本就發(fā)送預(yù)警日志。

如果昨天說的內(nèi)聯(lián)事件使用定時掃描,或許還能在觸發(fā)前攔截一部分,但對于腳本則完全不可能了。腳本元素一旦被掛載到主節(jié)點之下,就立即加載并執(zhí)行了。除非定時器開的特別短,能在腳本加載的過程中將其銷毀,或許還能攔截,否則一不留神就錯過了。

我們得尋找更高端的瀏覽器接口,能在元素創(chuàng)建或添加時,進行分析和攔截。

主動防御

在無所不能的 HTML5 里,這當然是能辦到的,它就是 MutationEvent。與其相關(guān)的有兩個玩意:一個叫 DOMNodeInserted 的事件,另一個則是 MutationObserver 類。

前者雖然是個事件,但即使阻止冒泡它,或調(diào)用 preventDefault 這些方法,仍然無法阻止元素被添加;而后者就不用說了,看名字就是一個觀察器,顯然優(yōu)先級會更低。

MutationEvent 試探

但不管能否實現(xiàn)我們的目標,既然有這么個東西,就先測試看看究竟能有多大的本領(lǐng)。

  1. <script> 
  2.     var observer = new MutationObserver(function(mutations) {  
  3.         console.log('MutationObserver:', mutations);  
  4.     });  
  5.     observer.observe(document, {  
  6.         subtree: true,  
  7.         childList: true  
  8.     });  
  9.  
  10.     document.addEventListener('DOMNodeInserted', function(e) {  
  11.         console.log('DOMNodeInserted:', e);  
  12.     }, true);  
  13. </script> 
  14.  
  15. <script>console.warn('site-in xss 1');</script> 
  16. <script src="http://www.etherdream.com/xss/out.js"></script> 
  17. <script>console.warn('site-in xss 2');</script> 
  18.  
  19. <button id="btn">創(chuàng)建腳本</button> 
  20. <script> 
  21.     btn.onclick = function() {  
  22.         var el = document.createElement('script');  
  23.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  24.         document.body.appendChild(el);  
  25.     };  
  26. </script> 

Run

出乎意料的是,MutationObserver 居然能逐一捕捉到頁面加載時產(chǎn)生的靜態(tài)元素,這在過去只能通過定時器才能勉強實現(xiàn)。同時為了更高效的記錄,MutationObserver 并非發(fā)現(xiàn)新元素就立即回調(diào),而是將一個時間片段里出現(xiàn)的所有元素,一起傳過來。這對性能來說是件好事,但顯然會損失一些優(yōu)先級。

再看DOMNodeInserted,它雖然無法捕獲到靜態(tài)元素,但在動態(tài)創(chuàng)建元素時,它比 MutationObserver 更早觸發(fā),擁有更高的優(yōu)先級。

靜態(tài)腳本攔截

接著再來嘗試,能否利用這兩個事件,銷毀可疑的腳本元素,以達到主動攔截的效果。

  1. <script> 
  2.     var observer = new MutationObserver(function(mutations) {  
  3.         mutations.forEach(function(mutation) {  
  4.  
  5.             var nodes = mutation.addedNodes;  
  6.             for (var i = 0; i < nodes.length; i++) {  
  7.                 var node = nodes[i];  
  8.  
  9.                 if (/xss/.test(node.src) || /xss/.test(node.innerHTML)) {  
  10.                     node.parentNode.removeChild(node);  
  11.                     console.log('攔截可疑模塊:', node);  
  12.                 }  
  13.             }  
  14.         });  
  15.     });  
  16.  
  17.     observer.observe(document, {  
  18.         subtree: true,  
  19.         childList: true  
  20.     });  
  21. </script> 
  22.  
  23. <script>console.warn('site-in xss 1');</script> 
  24. <script src="http://www.etherdream.com/xss/out.js"></script> 
  25. <script>console.warn('site-in xss 2');</script> 
  26.  
  27. <button id="btn">創(chuàng)建腳本</button> 
  28. <script> 
  29.     btn.onclick = function() {  
  30.         var el = document.createElement('script');  
  31.         el.src = 'http://www.etherdream.com/x\ss/out.js?dynamic';  
  32.         document.body.appendChild(el);  
  33.     };  
  34. </script> 

Run

又是一個出人意料的結(jié)果,所有靜態(tài)腳本被成功攔截了!

針對XSS漏洞的前端防火墻:可疑模塊攔截 

針對XSS漏洞的前端防火墻:可疑模塊攔截

 

然而這并非標準。FireFox 雖然攔截到腳本,但仍然執(zhí)行代碼了。

針對XSS漏洞的前端防火墻:可疑模塊攔截

不過對于預(yù)警系統(tǒng)來說,能夠發(fā)現(xiàn)問題也足夠了,可以攔截風(fēng)險那就再好不過。

動態(tài)腳本攔截

剛剛測試了靜態(tài)腳本的攔截,取得了不錯的成績。但在動態(tài)創(chuàng)建的元素上,和我們先前猜測的一樣,MutationObserver 因優(yōu)先級過低而無法攔截。

那就讓 DOMNodeInserted 來試試:

  1. <script> 
  2.     document.addEventListener('DOMNodeInserted', function(e) {  
  3.         var node = e.target;  
  4.  
  5.         if (/xss/.test(node.src) || /xss/.test(node.innerHTML)) {  
  6.             node.parentNode.removeChild(node);  
  7.             console.log('攔截可疑模塊:', node);  
  8.         }  
  9.     }, true);  
  10. </script> 
  11.  
  12. <button id="btn">創(chuàng)建腳本</button> 
  13. <script> 
  14.     btn.onclick = function() {  
  15.         var el = document.createElement('script');  
  16.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  17.         document.body.appendChild(el);  
  18.     };  
  19. </script> 

Run

遺憾的是,DOMNodeInserted 也沒能攔截動態(tài)腳本的執(zhí)行 —— 盡管能檢測到。經(jīng)過一番嘗試,所有瀏覽器都宣告失敗。

當然,能實時預(yù)警已滿足我們的需求了。但若能攔截動態(tài)腳本,整套系統(tǒng)防御力就更高了。

既然無法通過監(jiān)控節(jié)點掛載來攔截,我們不妨換一條路。問題總有解決的方案,就看簡單與否。

屬性攔截

仔細分析動態(tài)腳本創(chuàng)建的所有步驟:

  1. var el = document.createElement('script');  
  2. el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  3. document.body.appendChild(el); 

是哪一步觸發(fā)了掛載事件?顯然是最后行。要獲得比它更高的優(yōu)先級,我們只能往前尋找。

既然是動態(tài)創(chuàng)建腳本,賦予它 src 屬性必不可少。如果創(chuàng)建腳本只為賦值 innerHTML 的話,還不如直接 eval 代碼更簡單。

如果能在屬性賦值時進行攔截,那么我們即可阻止賦予可疑的 src 屬性。

類似 IE 有個 onpropertychange 事件,HTML5 里面也是有屬性監(jiān)聽接口的,并且就是剛剛我們使用的那個:MutationEvent。甚至還是那兩套方案:DOMAttrModified 和 MutationObserver。

在根節(jié)點上監(jiān)聽屬性變化,肯定會大幅影響頁面的性能,但我們還是先來看看是否可行。

先嘗試 MutationObserver:

  1. var observer = new MutationObserver(function(mutations) {  
  2.     console.log(mutations);  
  3. });  
  4. observer.observe(document, {  
  5.     subtree: true,  
  6.     attributes: true  
  7. });  
  8.  
  9. var el = document.createElement('script');  
  10. el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  11. document.body.appendChild(el); 

站外腳本執(zhí)行了,但奇怪的是,回調(diào)卻沒有觸發(fā)。原來,我們監(jiān)控的是 document 下的元素,而腳本賦值時還處于離屏狀態(tài),顯然無法將事件冒泡上來。

如果我們先 appendChild 再賦值 src 屬性,倒是可以捕獲到。但現(xiàn)實中調(diào)用順序完全不是我們說了算的。

同樣的,DOMAttrModified 也有這問題。

看來,事件這條路的局限性太大,我們得另辟蹊徑。

API 攔截

監(jiān)控屬性賦值的方式肯定不會錯,只是我們不能再用事件那套機制了。

想在修改屬性時觸發(fā)函數(shù)調(diào)用,除了事件外,另一個在傳統(tǒng)語言里經(jīng)常用到的、并且主流 JavaScript 也支持的,那就是Setter 訪問器。

當我們設(shè)置腳本元素 src 屬性時,理論上說 HTMLScriptElement.prototype.src 這個訪問器將被調(diào)用。如果我們重寫這個訪問器,即可在設(shè)置腳本路徑時將其攔截。

  1. <script> 
  2.     HTMLScriptElement.prototype.__defineSetter__('src', function(url) {  
  3.         console.log('設(shè)置路徑:', url);  
  4.     });  
  5. </script> 
  6.  
  7. <button id="btn">創(chuàng)建腳本</button> 
  8. <script> 
  9.     btn.onclick = function() {  
  10.         var el = document.createElement('script');  
  11.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  12.         document.body.appendChild(el);  
  13.     };  
  14. </script> 

Run

如果這套方案可行的話,一切都將迎刃而解。而且我們只監(jiān)聽腳本元素的 src 賦值,其他元素和屬性則完全不受影響,因此性能得到極大提升。

經(jīng)測試,F(xiàn)ireFox 和 IE 瀏覽器完全可行。我們事先保存原始的 setter 變量,然后根據(jù)策略,決定是否向上調(diào)用。

  1. <script> 
  2.     var raw_setter = HTMLScriptElement.prototype.__lookupSetter__('src');  
  3.  
  4.     HTMLScriptElement.prototype.__defineSetter__('src', function(url) {  
  5.         if (/xss/.test(url)) {  
  6.             if (confirm('試圖加載可疑模塊:\n\n' + url + '\n\n是否攔截?')) {  
  7.                 return;  
  8.             }                 
  9.         }  
  10.         raw_setter.call(this, url);  
  11.     });  
  12. </script> 
  13.  
  14. <button id="btn">創(chuàng)建腳本</button> 
  15. <script> 
  16.     btn.onclick = function() {  
  17.         var el = document.createElement('script');  
  18.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  19.         document.body.appendChild(el);  
  20.     };  
  21. </script> 

Run

針對XSS漏洞的前端防火墻:可疑模塊攔截

效果非常漂亮,然而現(xiàn)實卻令人遺憾 —— 我們的主流瀏覽器 Chrome 并不支持。由于無法操作原生訪問器,即使在原型鏈上重寫了 setter,實際賦值時仍不會調(diào)用我們的監(jiān)控程序。

先不急,若是拋棄原型鏈,直接在元素實例上定義訪問器又會如何?

  1. <button id="btn">創(chuàng)建腳本</button> 
  2. <script> 
  3.     btn.onclick = function() {  
  4.         var el = document.createElement('script');  
  5.  
  6.         el.__defineSetter__('src', function(url) {  
  7.             console.log('設(shè)置路徑:', url);  
  8.         });  
  9.  
  10.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  11.         document.body.appendChild(el);  
  12.     };  
  13. </script> 

run

這一回,Chrome 終于可以了。

針對XSS漏洞的前端防火墻:可疑模塊攔截

然而,這僅僅是測試?,F(xiàn)實中哪有這樣的機會,供我們裝上訪問器呢。

因此,我們只能把主動防御的時機再往前推,在元素創(chuàng)建時就調(diào)用我們的防御代碼。我們得重寫 createElement 這些能創(chuàng)建元素 API,只有這樣,才能第一時間里,給實例裝上我們的鉤子程序,為 Chrome 實現(xiàn)動態(tài)模塊的防御:

  1. <script> 
  2.     // for chrome  
  3.     var raw_fn = Document.prototype.createElement;  
  4.  
  5.     Document.prototype.createElement = function() {  
  6.  
  7.         // 調(diào)用原生函數(shù)  
  8.         var element = raw_fn.apply(this, arguments);  
  9.  
  10.         // 為腳本元素安裝屬性鉤子  
  11.         if (element.tagName == 'SCRIPT') {  
  12.             element.__defineSetter__('src', function(url) {  
  13.                 console.log('設(shè)置路徑:', url);  
  14.             });  
  15.         }  
  16.  
  17.         // 返回元素實例  
  18.         return element;  
  19.     };  
  20. </script> 
  21.  
  22. <button id="btn">創(chuàng)建腳本</button> 
  23. <script> 
  24.     btn.onclick = function() {  
  25.         var el = document.createElement('script');  
  26.         el.src = 'http://www.etherdream.com/xss/out.js?dynamic';  
  27.         document.body.appendChild(el);  
  28.     };  
  29. </script> 

Run

這樣,當元素創(chuàng)建時,就已帶有我們的屬性掃描程序了,Chrome 不支持的問題也迎刃而解。

事實上,除了重寫 property 訪問器,我們還得考慮通過 setAttribute 賦值 src 的情況。因此需整理出一套完善的瀏覽器鉤子程序。

重寫原生 API 看似很簡單,但如何才能打造出一個無懈可擊的鉤子系統(tǒng)呢?明天繼續(xù)講解。

責(zé)任編輯:藍雨淚 來源: FEX
相關(guān)推薦

2014-06-23 09:18:22

2014-06-24 09:46:08

2014-06-30 14:12:09

XSSXSS漏洞前端防護

2014-06-24 11:46:22

2010-01-12 11:58:14

Cisco防火墻拒絕服務(wù)漏洞

2010-09-14 10:19:39

2016-01-24 23:12:00

UFW防火墻攔截IP地址

2010-09-14 13:08:52

2010-12-21 18:04:26

2024-12-30 12:02:29

2010-12-08 09:29:27

下一代防火墻

2010-09-09 17:22:36

2010-05-24 17:49:56

2011-06-27 13:31:21

2019-07-18 11:26:13

防火墻網(wǎng)絡(luò)安全軟件

2011-04-18 13:50:43

2021-06-25 18:31:37

云防火墻

2021-09-06 11:46:42

Fortinet漏洞防火墻

2013-07-04 10:16:24

2011-03-25 11:18:51

點贊
收藏

51CTO技術(shù)棧公眾號