JavaScript防流量劫持-前端安全_js流量劫持怎么操作_onlyhom的博客-程序员秘密

技术标签: 前端安全  js  防止流量劫持  

劫持产生的原因和方式

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

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

  • 对正常网站加入额外的广告,这包括网页内浮层或弹出广告窗口;
  • 针对一些广告联盟或带推广链接的网站,加入推广尾巴;
  • 把我们的站点非法解析到其他的站点,比如我们在浏览器输入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请求请求一个网站页面的时候,网络运营商会在正常的数据流中插入精心设计的网络数据报文,让客户端(通常是浏览器)展示“错误”的数据,通常是一些弹窗,宣传性广告或者直接显示某网站的内容,大家应该都有遇到过。做法1、2就是通过这种方式

2、DNS劫持

我们通过域名访问网页的时候,都需要通过DNS服务器把域名解析到对应的服务器地址上,而用户上网的DNS服务器都是运营商分配的。所以,在这个节点上,运营商可以为所欲为。做法3就是通过这种方式

对于以上的劫持方式,我们作为前端的开发人员,通过javascript如何来做到有效的防护呢?

对于DNS劫持,由于发生在域名解析的时候,我们无法控制,javascript更无能为力。我们能做的就是拿起手机,投诉网络运营商,或者直接打工信部电话(12300)投诉。

http劫持防范

对于http劫持,运营商在实现上一般有以下几种做法

  • iframe嵌套展示原来正常网页
  • 在原html中插入js,再通过js脚本安插广告
  • 直接返回一个带广告的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,运营商的劫持无法达到目的,自然不会去做这样吃力不讨好的事情。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/oulihong123/article/details/94380938

智能推荐

C++的类型转换运算符(一)——static_cast 与 dynamic_cast_c++执行期类型识别_yang_yulei的博客-程序员秘密

类型转换是一种机制,让程序员能够暂时或永久性改变编译器对对象的解释。注意,这并不意味着程序员改变了对象本身,而只是改变了对对象的解释。在很多情况下,类型转换是合理的需求,可解决重要的兼容问题。因此,程序员经常需要让编译器按其所需的方式解释数据,让应用程序能够成功编译并执行。 C++编译器仍需向后兼容以确保遗留代码能够通过编译,因此支持下面这样的语法:int* pBuf = (int *

servlet跨域解决 ccess to XMLHttpRequest at ‘http://xxxx‘’ from origin‘null‘ has been blocked by CORS_ccess to xmlhttprequest at 'http://localhost:8080/_wangsiheng_47的博客-程序员秘密

servlet跨域解决 ccess to XMLHttpRequest at ‘http://xxxx‘’ from origin’null’ has been blocked by CORS项目场景:服务端是写的servlet,在编写AJAX对服务端请求时出现问题描述:报错代码:ccess to XMLHttpRequest at ‘http://localhost:8080/searchuser1?searchword=undefined’ from origin ‘null’ has be

SQL Server find filename from directory column_仙仙熊的博客-程序员秘密

env:Windows Server 2016       SQL Server 2016 SP2column裡面儲存的資料是檔案名稱與路徑,要怎麼順利把檔案名稱取出來?1.建立存放測試資料的表command:CREATE TABLE #DirTree(subdirectory NVARCHAR(200),depth INT,isfile BIT) 2.利用...

The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the assoc_笔尖的痕的博客-程序员秘密

异常信息:The Struts dispatcher cannot be found.  This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the request has passed through its servlet filt

mysql 中文乱码 解决方法集锦_svod的博客-程序员秘密

主要是针对 1.4x版本的一些乱码问题,其实新版本中错误也差不多,大家注意下编码问题。第一个方法: MySQL 4.1 中文乱码的问题 最近要将 MySQL 4.0 升级到 MySQL 4.1 ,发现了中文乱码的问题,希望以下见解对大家有用。 1. MySQL 4.1 在文字上有很大改进,它有了 Character Set 与 Collation

linux重置ilo,HP DL380 Gen9 服务器ilo密码忘记如何重置_热云数据的博客-程序员秘密

参考链接:HP厂家早就替我们准备好方案,可以在不重启服务器的情况下对ilo进行配置。这个工具就是hponcfg——HP Lights-Out Online Configuration Utility。该工具是HP提供的一个可以在Windows(包括GUI和命令行)/Linux系统中使用的工具,适用于所有具有iLO接口(包括iLO1、iLO2、iLO3、iLO4、iLO5)的HP ProLiant ...

随便推点

点云拼接注册_NT4.4的博客-程序员秘密

原文链接点云拼接,配准,注册有什么联系点云拼接,配准,注册说的是同一个概念,就是把不同位置的点云通过重叠部分的信息,变换到同一个位置。下面我们就用注册这个名词来描述这个过程。注册一般分为三类:粗注册,精细注册和全局注册。粗注册:一般用于注册两个位置相差很大的点云,比如两帧位于相机坐标系的点云。粗注册方法大致分为两类:有标记点粗注册和无标记点粗注册。标记点可以是用户手动标记的,也可以是物体扫...

机器学习-牛顿迭代法原理和公式推导_迭代算法求导数_taoKingRead的博客-程序员秘密

机器学习的本质是建立优化模型,通过优化方法,不断迭代参数向量,找到使目标函数最优的参数向量,最终建立模型。通常用到的优化方法:梯度下降方法、牛顿法、拟牛顿法等,这些优化方法的本质就是在更新参数。 牛顿迭代法又称为牛顿-拉弗森方法,实际上是由牛顿、拉弗森各自独立提出来的。牛顿-拉弗森方法提出来的思路就是利用切线是曲线的线性逼近这个思想,如下图所示: 随便找一个曲线上的A点(为什么随便找,根据切线是切点附近的...

巴菲特评科技股:投资 IBM 是个错误,还会增持苹果,亚马逊简直是奇迹_AI科技大本营的博客-程序员秘密

整理 | DavidZh北京时间 5 月 6 日,跨国投资及控股集团公司伯克希尔·哈撒韦(Berkshire Hathaway)在美国奥马哈总部召开了一年一次的全球股东大...

gnvm 管理npm_window下使用gnvm安装多版本node.js_thecakr的博客-程序员秘密

本文最后更新于2019-06-14,已超过 1年没有更新,如果文章内容、图片或者下载资源失效,请留言反馈,我会及时处理,谢谢!温馨提示:本文共899个字,读完预计3分钟。GNVM使用Go 语言编写的 Node.js 多版本管理器GNVM是一个简单的Node.js 多版本管理器,类似nvmnvmwnodist。特色单文件,不依赖于任何环境。下载即用,无需配置。彩色日志输出。支持多线程下载。内...

7-4 汽车加油问题 (20 分)_A snicker的博客-程序员秘密

题目来源:王晓东《算法设计与分析》一辆汽车加满油后可行驶 n公里。旅途中有若干个加油站。设计一个有效算法,指出应 在哪些加油站停靠加油,使沿途加油次数最少。输入格式:第一行有 2 个正整数n和 k(k&lt;=1000 ),表示汽车加满油后可行驶n公里,且旅途中有 k个加油站。 第二行有 k+1 个整数,表示第 k 个加油站与第k-1 个加油站之间的距离。 第 0 个加油站表示出发地,汽车已加满油。 第 k+1 个加油站表示目的地。输出格式:输出最少加油次数。如果无法到达目的地,则输出“No So

032一组惯导参考数据_惯导数据_魔方的块的博客-程序员秘密

  翻看严恭敏老师的博客发现一组实测惯导数据,特地下载下来用其工具箱处理了一下,肉眼看起来跟原图没有差别。到这算是终于有了一组珍贵的数据(实测数据,又有处理好的结果作参考)。一组数据可以做很多事,比如作为验证自己目前程序的数据。哈哈,收获不小,不敢独享,特来分享。注意,我贴出来的数据是读取完的,直接处理就可以,原数据为txt格式一同给出。另外,请尊重数据提供者。我的:严老师的:最后要...

推荐文章

热门文章

相关标签