zoukankan      html  css  js  c++  java
  • 【前端安全】JavaScript防流量劫持

    劫持产生的原因和方式

    在网页开发的访问过程中,http是我们主要的访问协议。我们知道http是一种无状态的连接。即没有验证通讯双方的身份,也没有验证信息的完整性,所以很容易受到篡改。运营商就是利用了这一点篡改了用户正常访问的网页,插入广告或者其他一些杂七杂八的东西,达到盈利的目的。

    运营商的一般做法有以下手段:

    1、对正常网站加入额外的广告,这包括网页内浮层或弹出广告窗口;

    2、针对一些广告联盟或带推广链接的网站,加入推广尾巴

    3、把我们的站点非法解析到其他的站点,比如我们在浏览器输入http://baidu.com,百度绑定的服务器ip地址是111.13.101.208,此时如果运营商的dns服务器将baidu.com的对应的ip地址改为qq的服务器ip 14.17.32.211,我们输入http://baidu.com就会跳转到QQ的页面。

    以上的手段,通过原理归纳为两种

    1、HTTP劫持

    当我们使用HTTP请求请求一个网站页面的时候,网络运营商会在正常的数据流中插入精心设计的网络数据报文,让客户端(通常是浏览器)展示错误的数据,通常是一些弹窗,宣传性广告或者直接显示某网站的内容,大家应该都有遇到过。做法12就是通过这种方式

    2、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,运营商的劫持无法达到目的,自然不会去做这样吃力不讨好的事情。

  • 相关阅读:
    Oracle笔记(三) Scott用户的表结构
    Oracle笔记(一) Oracle简介及安装
    Oracle笔记(七) 数据更新、事务处理、数据伪列
    Oracle笔记(六) 多表查询
    Oracle笔记(九) 表的创建及管理
    Oracle笔记(四) 简单查询、限定查询、数据的排序
    CentOS 6.3下部署LVS(NAT)+keepalived实现高性能高可用负载均衡
    PostgreSQL学习手册(十七) PL/pgSQL过程语言
    Oracle笔记(八) 复杂查询及总结
    Oracle笔记(十二) 集合、序列
  • 原文地址:https://www.cnblogs.com/caizhenbo/p/6836376.html
Copyright © 2011-2022 走看看