劫持產生的緣由和方式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請求請求一個網站頁面的時候,網絡運營商會在正常的數據流中插入精心設計的網絡數據報文,讓客戶端(一般是瀏覽器)展現「錯誤」的數據,一般是一些彈窗,宣傳性廣告或者直接顯示某網站的內容,你們應該都有遇到過。作法1、2就是經過這種方式安全
二、DNS劫持服務器
咱們經過域名訪問網頁的時候,都須要經過DNS服務器把域名解析到對應的服務器地址上,而用戶上網的DNS服務器都是運營商分配的。因此,在這個節點上,運營商能夠隨心所欲。作法3就是經過這種方式
對於以上的劫持方式,咱們做爲前端的開發人員,經過javascript如何來作到有效的防禦呢?
對於DNS劫持,因爲發生在域名解析的時候,咱們沒法控制,javascript更無能爲力。咱們能作的就是拿起手機,投訴網絡運營商,或者直接打工信部電話(12300)投訴。
http劫持防範
對於http劫持,運營商在實現上通常有如下幾種作法
1、iframe嵌套展現原來正常網頁
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