【前端安全】JavaScript防流量劫持

劫持產生的緣由和方式javascript

在網頁開發的訪問過程當中,http是咱們主要的訪問協議。咱們知道http是一種無狀態的鏈接。即沒有驗證通信雙方的身份,也沒有驗證信息的完整性,因此很容易受到篡改。運營商就是利用了這一點篡改了用戶正常訪問的網頁,插入廣告或者其餘一些雜七雜八的東西,達到盈利的目的。html

運營商的通常作法有如下手段:前端

1、對正常網站加入額外的廣告,這包括網頁內浮層或彈出廣告窗口;html5

2、針對一些廣告聯盟或帶推廣連接的網站,加入推廣尾巴java

3、把咱們的站點非法解析到其餘的站點,好比咱們在瀏覽器輸入http://baidu.com,百度綁定的服務器ip地址是111.13.101.208,此時若是運營商的dns服務器將baidu.com的對應的ip地址改成qq的服務器ip 14.17.32.211,咱們輸入http://baidu.com就會跳轉到QQ的頁面。node

以上的手段,經過原理概括爲兩種web

一、HTTP劫持瀏覽器

當咱們使用HTTP請求請求一個網站頁面的時候,網絡運營商會在正常的數據流中插入精心設計的網絡數據報文,讓客戶端(一般是瀏覽器)展現錯誤的數據,一般是一些彈窗,宣傳性廣告或者直接顯示某網站的內容,你們應該都有遇到過。作法12就是經過這種方式安全

二、DNS劫持服務器

咱們經過域名訪問網頁的時候,都須要經過DNS服務器把域名解析到對應的服務器地址上,而用戶上網的DNS服務器都是運營商分配的因此,在這個節點上,運營商能夠隨心所欲。作法3就是經過這種方式

對於以上的劫持方式,咱們做爲前端的開發人員,經過javascript如何來作到有效的防禦呢?

對於DNS劫持,因爲發生在域名解析的時候,咱們沒法控制,javascript更無能爲力。咱們能作的就是拿起手機,投訴網絡運營商,或者直接打工信部電話(12300)投訴。

http劫持防範

對於http劫持,運營商在實現上通常有如下幾種作法

1iframe嵌套展現原來正常網頁

2、在原html中插入js,再經過js腳本安插廣告

3、直接返回一個帶廣告的HTML

首先咱們來看頁面被嵌入了 iframe 狀況。網絡運營商爲了儘量地減小植入廣告對原有網站頁面的影響,一般會經過把原有網站頁面放置到一個和原頁面相同大小的 iframe 裏面去,那麼就能夠經過這個 iframe 來隔離廣告代碼對原有頁面的影響。這種狀況比較容易處理。咱們只要判斷咱們的頁面是否被嵌套在iframe中便可。Window對象中有兩個屬性self(指向自己的窗口),top(指向頂層的窗口)能夠幫咱們來識別判斷

咱們能夠這樣簡單判斷:

if (window.self != window.top) {
  var url = location.href;
    top.location = url;
}

可是,有時候咱們在實際業務中,咱們的頁面確實須要被嵌套在iframe中推廣,上面的判斷會致使頁面沒法嵌套,這時候咱們能夠採用配置域名白名單的方式來解決

複製代碼
var avoidIframeNest = {
    whiteList : [],
    init: function(whiteList){
        if(Object.prototype.toString.call(whiteList) == "[object Array]"){
            this.whiteList = whiteList;
        }
        this.redirect();
    },
    redirect: function(){
        if(self != top){
            var parentUrl = document.referrer;
            //是否在白名單內
            for(var i = 0 ,length = this.whiteList.length ; i < length ; ++ i){
                var reg = new RegExp(this.whiteList[i],'i');

                if(reg.test(parentUrl)){
                  return;
                }
            }
            //頁面跳轉
            var url = location.href;
            top.location = url;
        }
    }
}
複製代碼

經過配置白名單的方式,比較適合於咱們常常用到的域名,一般咱們會遇到這樣的需求,合做方要求嵌套咱們的頁面,咱們若是將合做方也加入到咱們白名單,一方面會致使白名單很長,另外一方面咱們須要手動去改代碼,這樣很不方便。這種狀況,咱們能夠在嵌套的url上加上域名的參數判斷,要求嵌套頁面帶上域名參數,若是匹配,就認爲合法。

複製代碼
var avoidIframeNest = {
    whiteList : [],
    init: function(whiteList){
        if(Object.prototype.toString.call(whiteList) == "[object Array]"){
            this.whiteList = whiteList;
        }
        this.redirect();
    },
    redirect: function(){
        if(self != top){
            var parentUrl = document.referrer;
            //是否在白名單內
            for(var i = 0 ,length = this.whiteList.length ; i < length ; ++ i){
                var reg = new RegExp(this.whiteList[i],'i');

                if(reg.test(parentUrl)){
                  return;
                }
            }

            //判斷URL是否帶指定參數
            var iframeDomain = this.getUrlParam('iframe_domain');
            if(iframeDomain && parentUrl.indexOf(iframeDomain) != -1){
                return;
            }
            //頁面跳轉
            var url = location.href;
            top.location = url;
        }
    },
    getUrlParam : function(key) {
        var regStr = "^.*[\\?|\\&]" + key + "\\=([^\\&]*)",
            url = location.href;
        reg = new RegExp(regStr,'i');;
        var ret = url.match(reg);
        if (ret != null) {
            return decodeURIComponent(ret[1]);
        } else {
            return "";
        }
    }
}

avoidIframeNest.init(['baidu.com']);
複製代碼

經過上述的方法,基本能夠解決iframe嵌套問題

對於js注入問題,通常都會在頁面中插入圖片標籤,展現廣告,誘導用戶點擊。針對這種方式,咱們能夠經過監控頁面插入的圖片內容來檢測。這裏,咱們能夠利用HTML5的新特性MutationObserver window下的DOMNodeInserted事件

Mutation Observer(變更觀察器)是監視DOM變更的接口。當DOM對象樹發生任何變更時,Mutation Observer會獲得通知。具體的介紹能夠參考:  

能夠監聽某個 DOM 範圍內的結構變化

http://www.cnblogs.com/jscode/p/3600060.html

DOMNodeInserted顧名思義,能夠監聽某個 DOM 範圍內的結構變化,這個特性只有在firefox的低版本和webkit中使用,IE不支持,這裏咱們能夠做爲低版本瀏覽器的兼容實現。

複製代碼
var validInsertImg = {
    httpReg : /^http:\/\/(.*\.baidu\.com|.*\.netwin\.com)\//,
    //驗證非法圖片
    validIllegalityImg : function(src){
        var httpReg = this.httpReg;
        return !httpReg.test(src);
    },
    init : function(){
        this.monitor();
    },
    monitor: function(){
        var MutationObserver = window.MutationObserver ||
        window.WebKitMutationObserver || 
        window.MozMutationObserver;
        var mutationObserverSupport = !!MutationObserver;
        //html5監控變化屬性
        if(!mutationObserverSupport){
            this.mutationListen(MutationObserver);
        }else{
            this.insertedListen();
        }
    },
    insertedListen : function(){
        var that = this;
        document.addEventListener('DOMNodeInserted', function(e) {
            var dom = e ? e.srcElement : document.documentElement;
            if (!dom.outerHTML) {
                return;
            }
            var imgList = (dom.nodeName.toUpperCase() == 'IMG') ? [dom] : dom.getElementsByTagName('img');
            if (!imgList || imgList.length == 0) {
                return;
            }
             for (var i = 0; i < imgList.length; i++) {
                   that.removeNode(imgList[i]);
            }
        });
    },
    mutationListen: function(MutationObserver){
        var that = this;
        var observer = new MutationObserver(function(mutations){
            mutations.forEach(function(mutation){
                var nodes = mutation.addedNodes;
                for(var i = 0 ; i < nodes.length ; i++){
                    var node = nodes[i];
                    that.removeNode(node);
                }
            })
        })
        observer.observe(document, {
          subtree: true,
          childList: true
        });

    },

    //刪除node
    removeNode : function(node){
        if(node.nodeName.toUpperCase() == 'IMG'){
            var src = node.src;
            if(this.validIllegalityImg(src)){
                node.parentNode.removeChild(node);
                  console.log('攔截可疑靜態腳本:', node.src);
            }
        }
    }
}

validInsertImg.init();

body = document.getElementsByTagName('body')[0];
 var img = document.createElement('img');
     img.setAttribute('src','http://m.baidu.com/img/b')
      body.appendChild(img);

 var img1 = document.createElement('img');
     img1.setAttribute('src','/YTRYTRY/A.PNG')
      body.appendChild(img1);
複製代碼

對於在返回html內容中插入廣告,咱們能夠借鑑注入的方式,進入頁面就檢測的img圖片路徑是否在白名單內

以上方法,都是針對運營商劫持的經常使用手段進行的一些黑科技操做。只能儘可能的減小劫持給咱們帶來的負面影響。針對劫持問題,最好的辦法就是全站升級https的方式,驗證通信雙方的身份以及信息的安全性。

可是https也不能徹底的解決劫持問題,若是https頁面被劫持,瀏覽器會出現空白頁面或者提示不安全,沒法顯示正常的內容。這也會影響到用戶的體驗。可是仍是推薦使用https,若是大部分的網站都使用了https,運營商的劫持沒法達到目的,天然不會去作這樣吃力不討好的事情。

 原文:https://www.cnblogs.com/caizhenbo/p/6836376.html

相關文章
相關標籤/搜索