黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

XSS 前端防火墻 —— 內(nèi)聯(lián)事件攔截

系統(tǒng) 2416 0

關(guān)于 XSS 怎樣形成、如何注入、能做什么、如何防范,前人已有無(wú)數(shù)的探討,這里就不再累述了。本文介紹的則是另一種預(yù)防思路。
? ?? ??幾乎每篇談?wù)?XSS 的文章,結(jié)尾多少都會(huì)提到如何防止,然而大多萬(wàn)變不離其宗。要轉(zhuǎn)義什么,要過(guò)濾什么,不要忘了什么之類的。盡管都是眾所周知的道理,但 XSS 漏洞十幾年來(lái)幾乎從未中斷過(guò),不乏一些大網(wǎng)站也時(shí)常爆出,小網(wǎng)站更是家常便飯。

預(yù)警系統(tǒng)
? ?? ??事實(shí)上,至今仍未有一勞永逸的解決方案,要避免它依舊使用最古老的土辦法,逐個(gè)的過(guò)濾。然而人總有疏忽的時(shí)候,每當(dāng)產(chǎn)品迭代更新時(shí),難免會(huì)遺漏一些新字段,導(dǎo)致漏洞被引入。
? ?? ??即使圣人千慮也有一失,程序出 BUG 完全可以理解,及時(shí)修復(fù)就行。但令人費(fèi)解的是,問(wèn)題出現(xiàn)到被發(fā)現(xiàn),卻要經(jīng)過(guò)相當(dāng)長(zhǎng)的時(shí)間。例如不久前貼吧 XSS 蠕蟲(chóng)腳本,直到大規(guī)模爆發(fā)后經(jīng)用戶舉報(bào),最終才得知。其他網(wǎng)站大多也類似,直到白帽子們挖掘出漏洞,提交到安全平臺(tái)上,最終廠商才被告知。若遇到黑客私下留著這些漏洞慢慢利用,那只能聽(tīng)天由命了。
? ?? ??因此,要是能有一套實(shí)時(shí)的預(yù)警系統(tǒng),那就更好了。即使無(wú)法阻止漏洞的發(fā)生,但能在漏洞觸發(fā)的第一時(shí)間里,通知開(kāi)發(fā)人員,即可在最短的時(shí)間里修復(fù),將損失降到最低。各式各樣的應(yīng)用層防火墻,也由此產(chǎn)生。
? ?? ??不過(guò),和傳統(tǒng)的系統(tǒng)漏洞不同,XSS 最終是在用戶頁(yè)面中觸發(fā)的。因此,我們不妨嘗試使用前端的思路,進(jìn)行在線防御。

DOM 儲(chǔ)存型 XSS
? ?? ??先來(lái)假設(shè)一個(gè)有 BUG 的后臺(tái),沒(méi)有很好處理用戶輸入的數(shù)據(jù),導(dǎo)致 XSS 能被注入到頁(yè)面:

      <img src="{路徑}" />

<img src="{路徑" onload="alert(/xss/)}" />
    

?

? ?? ??只轉(zhuǎn)義尖括號(hào),卻忘了引號(hào),是 XSS 里最為常見(jiàn)的。攻擊者們可以提前關(guān)閉屬性,并添加一個(gè)極易觸發(fā)的內(nèi)聯(lián)事件,跨站腳本就這樣被輕易執(zhí)行了。
? ?? ??那么,我們能否使用前端腳本來(lái)捕獲,甚至攔截呢?

被動(dòng)掃描
? ?? ??最簡(jiǎn)單的辦法,就是把頁(yè)面里所有元素都掃描一遍,檢測(cè)那些 on 開(kāi)頭的內(nèi)聯(lián)屬性,看看是不是存在異常:
? ?? ??例如字符數(shù)非常多,正常情況下這是很少出現(xiàn)的,但 XSS 為了躲避轉(zhuǎn)義有時(shí)會(huì)編碼的很長(zhǎng);例如出現(xiàn)一些 XSS 經(jīng)常使用的關(guān)鍵字,但在實(shí)際產(chǎn)品里幾乎不會(huì)用到的。這些都可以作為漏洞出現(xiàn)的征兆,通知給開(kāi)發(fā)人員。
? ?? ??不過(guò),土辦法終究存在很大的局限性。在如今清一色的 AJAX 時(shí)代,頁(yè)面元素從來(lái)都不是固定的。伴隨著用戶各種交互,新內(nèi)容隨時(shí)都可能動(dòng)態(tài)添加進(jìn)來(lái)。即使換成定期掃描一次,XSS 也可能在定時(shí)器的間隔中觸發(fā),并銷毀自己,那樣永遠(yuǎn)都無(wú)法跟蹤到了。況且,頻繁的掃描對(duì)性能影響也是巨大的。
? ?? ??如同早期的安全軟件一樣,每隔幾秒掃描一次注冊(cè)表啟動(dòng)項(xiàng),不僅費(fèi)性能,而且對(duì)惡意軟件幾乎不起作用;但之后的主動(dòng)防御系統(tǒng)就不同了,只有在真正調(diào)用 API 時(shí)才進(jìn)行分析,不通過(guò)則直接攔截,完全避免了定時(shí)器的間隔遺漏。
? ?? ??因此,我們需要這種類似的延時(shí)策略 —— 僅在 XSS 即將觸發(fā)時(shí)對(duì)其分析,對(duì)不符合策略的元素,進(jìn)行攔截或者放行,同時(shí)發(fā)送報(bào)警到后臺(tái)日志。

主動(dòng)防御
? ?? ??『主動(dòng)防御』,這概念放在前端腳本里似乎有些玄乎。但不難發(fā)現(xiàn),這僅僅是執(zhí)行優(yōu)先級(jí)的事而已 —— 只要防御程序能運(yùn)行在其他程序之前,我們就有了可進(jìn)可退的主動(dòng)權(quán)。對(duì)于無(wú)比強(qiáng)大的 HTML5 和靈活多變的 JavaScript,這些概念都可以被玩轉(zhuǎn)出來(lái)。
? ?? ??繼續(xù)回到剛才討論的內(nèi)聯(lián)事件 XSS 上來(lái)。瀏覽器雖然沒(méi)提供可操控內(nèi)聯(lián)事件的接口,但內(nèi)聯(lián)事件的本質(zhì)仍是一個(gè)事件,無(wú)論怎樣變化都離不開(kāi) DOM 事件模型。
? ?? ??扯到模型上面,一切即將迎刃而解。模型是解決問(wèn)題的最靠譜的辦法,尤其是像?DOM-3-Event( http://www.w3.org/TR/DOM-Level-3-Events/ )這種早已制定的模型,其穩(wěn)定性毋庸置疑。
? ?? ??即便沒(méi)仔細(xì)閱讀官方文檔,但凡做過(guò)網(wǎng)頁(yè)的都知道,有個(gè) addEventListener 的接口,并取代了曾經(jīng)一個(gè)古老的叫 attachEvent 的東西。盡管只是新增了一個(gè)參數(shù)而已,但正是這個(gè)差別成了人們津津樂(lè)道的話題。每當(dāng)面試談到事件時(shí),總少不了考察下這個(gè)新參數(shù)的用途。盡管在日常開(kāi)發(fā)中很少用到它。


? ?? ??關(guān)于事件捕獲和冒泡的細(xì)節(jié),就不多討論了。下面的這段代碼,或許能激發(fā)你對(duì)『主動(dòng)防御』的遐想。

      <button onclick="console.log('target')">CLICK ME</button>
<script>
    document.addEventListener('click', function(e) {
        console.log('bubble');
    });

    document.addEventListener('click', function(e) {
        console.log('capture');
        //e.stopImmediatePropagation();
    }, true);
</script>
    

?

Run( http://jsfiddle.net/zjcqoo/v9wm5/ )

? ?? ??盡管按鈕上直接綁了一個(gè)內(nèi)聯(lián)的事件,但事件模型并不買賬,仍然得按標(biāo)準(zhǔn)的流程走一遍。capture,target,bubble,模型就是那樣固執(zhí)。
? ?? ??不過(guò),把那行注釋的代碼恢復(fù),結(jié)果就只剩 capture 了。這個(gè)簡(jiǎn)單的道理大家都明白,也沒(méi)什么好解釋的。
? ?? ??但仔細(xì)揣摩下,這不就是『主動(dòng)防御』的概念嗎?捕獲程序運(yùn)行在內(nèi)聯(lián)事件觸發(fā)之前,并且完全有能力攔截之后的調(diào)用。

? ?? ??上面的 Demo 只是不假思索攔截了所有的事件。如果我們?cè)偌右恍┎呗耘袛啵蛟S就更明朗了:

      <button onclick="console.log('xss')">CLICK ME</button>
<script>
    document.addEventListener('click', function(e) {
        console.log('bubble');
    });

    document.addEventListener('click', function(e) {
        var element = e.target;
        var code = element.getAttribute('onclick');

        if (/xss/.test(code)) {
            e.stopImmediatePropagation();
            console.log('攔截可疑事件:', code);
        }
    }, true);
</script>
    

?

?

Run( http://jsfiddle.net/zjcqoo/r93Sv/ )

? ?? ??我們先在捕獲階段掃描內(nèi)聯(lián)事件字符,若是出現(xiàn)了『xss』這個(gè)關(guān)鍵字,后續(xù)的事件就被攔截了;換成其他字符,仍然繼續(xù)執(zhí)行。同理,我們還可以判斷字符長(zhǎng)度是否過(guò)多,以及更詳細(xì)的黑白名單正則。



? ?? ??怎么樣,一個(gè)主動(dòng)防御的原型誕生了吧。
? ?? ??不過(guò),上面的片段還有個(gè)小問(wèn)題,就是把事件的冒泡過(guò)程也給屏蔽了,而我們僅僅想攔截內(nèi)聯(lián)事件而已。解決辦法也很簡(jiǎn)單,把 e.stopImmediatePropagation() 換成 element.onclick = null 就可以了。
? ?? ??當(dāng)然,目前這只能防護(hù) onclick,而現(xiàn)實(shí)中有太多的內(nèi)聯(lián)事件。鼠標(biāo)、鍵盤、觸屏、網(wǎng)絡(luò)狀態(tài)等等,不同瀏覽器支持的事件也不一樣,甚至還有私有事件,難道都要事先逐一列出并且都捕獲嗎?是的,可以都捕獲,但不必事先都列出來(lái)。
? ?? ??因?yàn)槲覀儽O(jiān)聽(tīng)的是 document 對(duì)象,瀏覽器所有內(nèi)聯(lián)事件都對(duì)應(yīng)著 document.onxxx 的屬性,因此只需運(yùn)行時(shí)遍歷一下 document 對(duì)象,即可獲得所有的事件名。

      <img src="*" onerror="console.log('xss')" />
<script>
    function hookEvent(onevent) {
        document.addEventListener(onevent.substr(2), function(e) {
            var element = e.target;
            if (element.nodeType != Node.ELEMENT_NODE) {
                return;
            }
            var code = element.getAttribute(onevent);
            if (code && /xss/.test(code)) {
                element[onevent] = null;
                console.log('攔截可疑事件:', code);
            }
        }, true);
    }

    console.time('耗時(shí)');
    for (var k in document) {
        if (/^on/.test(k)) {
            //console.log('監(jiān)控:', k);
            hookEvent(k);
        }
    }
    console.timeEnd('耗時(shí)');
</script>
    

?

Run( http://jsfiddle.net/zjcqoo/yNH7V/ )



? ?? ??現(xiàn)在,無(wú)論頁(yè)面中哪個(gè)元素觸發(fā)哪個(gè)內(nèi)聯(lián)事件,都能預(yù)先被我們捕獲,并根據(jù)策略可進(jìn)可退了。

性能優(yōu)化
? ?? ??或許有些事件沒(méi)有必要捕獲,例如視頻播放、音量調(diào)節(jié)等,但就算全都捕捉也耗不了多少時(shí)間,基本都在 1ms 左右。
? ?? ??當(dāng)然,注冊(cè)事件本來(lái)就花不了多少時(shí)間,真正的耗費(fèi)都算在回調(diào)上了。盡管大多數(shù)事件觸發(fā)都不頻繁,額外的掃描可以忽律不計(jì)。但和鼠標(biāo)移動(dòng)相關(guān)的事件那就不容忽視了,因此得考慮性能優(yōu)化。
? ?? ??顯然,內(nèi)聯(lián)事件代碼在運(yùn)行過(guò)程中幾乎不可能發(fā)生變化。使用內(nèi)聯(lián)事件大多為了簡(jiǎn)單,如果還要在運(yùn)行時(shí) setAttribute 去改變內(nèi)聯(lián)代碼,完全就是不可理喻的。因此,我們只需對(duì)某個(gè)元素的特定事件,掃描一次就可以了。之后根據(jù)標(biāo)志,即可直接跳過(guò)。

      <div style="width:100%; height:100%; position:absolute" onmouseover="console.log('xss')"></div>
<script>
    function hookEvent(onevent) {
        document.addEventListener(onevent.substr(2), function(e) {
            var element = e.target;

            // 跳過(guò)已掃描的事件
            var flags = element['_flag'];
            if (!flags) {
                flags = element['_flag'] = {};
            }
            if (typeof flags[onevent] != 'undefined') {
                return;
            }
            flags[onevent] = true;

            if (element.nodeType != Node.ELEMENT_NODE) {
                return;
            }
            var code = element.getAttribute(onevent);
            if (code && /xss/.test(code)) {
                element[onevent] = null;
                console.log('攔截可疑代碼:', code);
            }
        }, true);
    }

    for (var k in document) {
        if (/^on/.test(k)) {
            hookEvent(k);
        }
    }
</script>
    

?

Run( http://jsfiddle.net/zjcqoo/9chsb/ )



? ?? ??這樣,之后的掃描僅僅是判斷一下目標(biāo)對(duì)象中的標(biāo)記而已。即使瘋狂晃動(dòng)鼠標(biāo),CPU 使用率也都忽略不計(jì)了。
? ?? ??到此,在 XSS 內(nèi)聯(lián)事件這塊,我們已實(shí)現(xiàn)主動(dòng)防御。
? ?? ??對(duì)于有著大量字符,或者出現(xiàn)類似 String.fromCharCode,$.getScript 這類典型 XSS 代碼的,完全可以將其攔截;發(fā)現(xiàn)有 alert(/xss/),alert(123) 這些測(cè)試代碼,可以暫時(shí)放行,并將日志發(fā)送到后臺(tái),確定是否能夠復(fù)現(xiàn)。
? ?? ??如果復(fù)現(xiàn),說(shuō)明已有人發(fā)現(xiàn) XSS 并成功注入了,但還沒(méi)大規(guī)模開(kāi)始利用。程序猿們趕緊第一時(shí)間修 BUG 吧,讓黑客忙活一陣子后發(fā)現(xiàn)漏洞已經(jīng)修復(fù)了:)

字符策略的缺陷
? ?? ??但是,光靠代碼字符串來(lái)判斷,還是會(huì)有疏漏的。尤其是黑客們知道有這么個(gè)玩意存在,會(huì)更加小心了。把代碼轉(zhuǎn)義用以躲避關(guān)鍵字,并將字符存儲(chǔ)在其他地方,以躲過(guò)長(zhǎng)度檢測(cè),即可完全繞過(guò)我們的監(jiān)控了:

      <img src="*" onerror="window['ev'+'al'](this.align)" align="alert('a mass of code...')">
    

?

? ?? ??因此,我們不僅需要分析關(guān)鍵字。在回調(diào)執(zhí)行時(shí),還需監(jiān)控 eval、setTimeout('...') 等這類能解析代碼的函數(shù)被調(diào)用。
? ?? ??不過(guò),通常不會(huì)注入太多的代碼,而是直接引入一個(gè)外部腳本,既簡(jiǎn)單又靠譜,并且能實(shí)時(shí)修改攻擊內(nèi)容:

      <img src="*" onerror="$['get'+'Script'](...)">
    

?


? ?? ?以上就是本次的討論,稍后討論如何攔截可疑的外部模塊。

轉(zhuǎn)自: http://anquan.baidu.com/bbs/thread-130640-1-1.html

XSS 前端防火墻 —— 內(nèi)聯(lián)事件攔截


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論