前端页面劫持和反劫持_xuyuwas的博客-程序员宅基地

技术标签: 扩展  页面劫持  反劫持  前端  劫持  

前端页面劫持和反劫持

页面劫持

使用HTTP请求请求一个网站页面的时候,网络运营商会在正常的数据流中插入精心设计的网络数据报文,让客户端(通常是浏览器)展示“错误”的数据,通常是一些弹窗,宣传性广告或者直接显示某网站的内容。

常见劫持手段

跳转型劫持:

用户输入地址A,但是跳转到地址B

为了获取流量,一些电商或者类似百度这样需要流量合作的网站都会有自己的联盟系统,通过给予一些奖励来获取导流,比如:百度或者电商会有渠道分成。

为了区分哪些是第三方给予导流过来的,通常会在url地址增加类似source、from之类的参数,或者进入页面之前通过「中间页」种cookie。

这样,当用户输入一个正常网址的时候,劫持方会在网络层让其跳转到带分成或者渠道号的「中间页」或者带渠道号的页面。这样用户进行下单或者搜索等行为,劫持方会得到「佣金」。

DNS劫持:在DNS服务器中,将www.xxx.com的域名对应的IP地址进行了变化。你解析出来的域名对应的IP,在劫持前后不一样;

中间人劫持就发生在第三步:由于恶意攻击者控制了你的网关,当你发送了一个查找freebuf.com的IP的请求的时候,中间人拦截住,并返回给你一个恶意网址的IP,你的浏览器就会把这个IP当做你想要访问的域名的IP!!这个IP是攻击者搭建的一个模仿了目标网站前端界面的界面,当你在该界面输入用户名密码或者付款操作的时候,就会中招。

注入型劫持:

有别于跳转型型劫持,指通过在正常的网页中注入广告代码(js、iframe等),实现页面弹窗提醒或者底部广告等,又分为下面三个小类:

1.注入js类劫持:
在正常页面注入劫持的js代码实现的劫持;注入js的方式可以通过 document.write或者直接改html代码片段等方式,给页面增加外链js,为了做到更难检测,有些运营商会捏造一个不存在的url地址,从而不被过滤或者检测。

案例1:运营商会用自己识别的ip或者域名做js网址,wap.zjtoolbar.10086.cn这类只有在浙江移动网络下才会被解析出来,同理ip也是

案例2:运营商很聪明,知道页面可以检测所有外链js的域名,比如:m.baidu.com我只允许m.baidu.com/static的外链js,其他js都会被记录反馈;为了不被检测出来,我遇见个case电信会访问一个不存在的地址,比如:m.baidu.com/static/abc.js,这个地址在运营商直接返回劫持的js代码,请求不会发到百度的服务器。

2.iframe类劫持:
将正常页面嵌入iframe或者页面增加iframe页面;一般是通过热门关键词之类做SEO,打开网站实际去了广告之类没有任何实际内容,而页面却是内嵌了一个其他网站,我们要是识别出来不被内嵌就需要检测。

3.篡改页面类劫持:
正常页面出现多余的劫持网页标签,导致页面整体大小发生变化;

HTTP劫持:标识HTTP连接。在天上飞的很多连接中,有许多种协议,第一步做的就是在TCP连接中,找出应用层采用了HTTP协议的连接,进行标识;篡改HTTP响应体,可以通过网关来获取数据包进行内容的篡改;抢先回包,将篡改后的数据包抢先正常站点返回的数据包先到达用户侧,这样后面正常的数据包在到达之后会被直接丢弃。

劫持检测方法

1、跳转型劫持

跳转型劫持如果用单纯靠Web页面进行检测比较困难,当时我们做检测是在手机百度(手百)内做检测,所以比较简单,用户输入搜索词(query),打开百度的页面URL,然后当页面加载结束,APP对比访问的URL是否是之前要访问的URL,如果URL不一致,则记录上报。

2、注入js类页面

  • 改写 document.write方法
  • 遍历页面 script标签,给外链js增加白名单,不在白名单内js外链都上报
  • 重写 Element.prototype.setAttribute,我们发现这里用到了 setAttribute 方法,如果我们能够改写这个原生方法,监听设置 src 属性时的值,通过黑名单或者白名单判断它,就可以判断该标签的合法性了。

MutationObserver 是 HTML5 新增的 API,功能很强大,给开发者们提供了一种能在某个范围内的 DOM 树发生变化时作出适当反应的能力。就是 MutationObserver 在观测时并非发现一个新元素就立即回调,而是将一个时间片段里出现的所有元素,一起传过来。所以在回调中我们需要进行批量处理。而且,其中的 callback 会在指定的 DOM 节点(目标节点)发生变化时被调用。在调用时,观察者对象会传给该函数两个参数,第一个参数是个包含了若干个 MutationRecord 对象的数组,第二个参数则是这个观察者对象本身。

var observer = new MutationObserver(function (mutations, observer) {
  mutations.forEach(function(mutation) {
    console.log(mutation);
  });
});

var article = document.querySelector('article');

var  options = {
  'childList': true,
  'attributes':true
} ;

observer.observe(article, options);

// 保存原有接口
var old_setAttribute = Element.prototype.setAttribute;
 
// 重写 setAttribute 接口
Element.prototype.setAttribute = function(name, value) {
 
  // 匹配到 <script src='xxx' > 类型
  if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {
    // 白名单匹配
    if (!whileListMatch(whiteList, value)) {
      console.log('拦截可疑模块:', value);
      return;
    }
  }
   
  // 调用原始接口
  old_setAttribute.apply(this, arguments);
};
 
// 建立白名单
var whiteList = [
'www.yy.com',
'res.cont.yy.com'
];
 
/**
 * [白名单匹配]
 * @param  {[Array]} whileList [白名单]
 * @param  {[String]} value    [需要验证的字符串]
 * @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
 */
function whileListMatch(whileList, value) {
  var length = whileList.length,
  for (i = 0; i < length; i++) {
    // 建立白名单正则
    var reg = new RegExp(whiteList[i], 'i');
 
    // 存在白名单中,放行
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

3、检测是否被iframe嵌套

window.self:返回一个指向当前 window 对象的引用。
window.top:返回窗口体系中的最顶层窗口的引用。

if (self != top) {
  // 我们的正常页面
  var url = location.href;
  // 父级页面重定向
  top.location = url;
}

4、特殊方法

前面提到类似电信捏造在白名单内的js URL和篡改页面内容的,我们用上面提到的方法检测不到这些信息,如果是在APP内,可以做的事情就比较多了,除了上面之外,还可以比较页面的 content-length。当时手百的做法是:

在用户开始输入query的时候,APP访问一个空白页面,页面内只有html、title、head、body、script,而script标签内主要代码就是嗅探是否被劫持。

因为一般劫持不会针对某个页面,而是针对整个网站域名,所以我们的空白页面也会被劫持。

劫持防御

最简单粗暴的就是直接上 HTTPS,一劳永逸。再就是取证,去打官司或者警告渠道作弊者。除此之外,我们还可以继续利用空白页面做劫持检测。

手百在没有全量https时期(毕竟全站https牵扯的工作量不小),利用空白页面嗅探出当前网络环境存在劫持风险的时候,那么就通过调用客户端的接口,告诉客户端本次启动期间使用 https,这样既可以降低劫持风险,又可以通过这个页面小流量测试https数据,将来https全量后,还可以通过空白页面将老版本的APP全量打开https

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

智能推荐

Linux驱动学习笔记之一——高精度定时器(2)_bingqingsuimeng的博客-程序员宅基地

二、相关的接口代码定时器初始化之后,进行设定定时器的到期时间,并启动定时器,函数声明代码hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode),timer代表将要被添加的定时器,tim代表到期时间,mode代表定时器模式。如果启动成功,则返回0,否则返回1。如果要取消一个设置好的定时器,

江苏机器人竞赛南航_中国青少年机器人竞赛_莹石的博客-程序员宅基地

在金珠小学是广东省首批“科普中国e站”建设单位,学校发挥青少年科学教育特色,为新时代科学传播插上“e翅膀”,做到线上与线下结合,把握科技发展脉动,紧盯科技创新趋势,推进科普教育信息化。科普展示屏,传播科学知识“让科技知识在网上和生活中流行!”瞧,一下课,孩子们就围拢在电子阅览屏旁边,正在津津有味地观看科普视频呢!金珠小学分别在总校区和华美校区的校务公开栏旁边安装一体机,建设科普电子阅览屏。师生、家...

DevOps,不是一个传说!_a13393665983的博客-程序员宅基地

DevOps,不是一个传说! DevOps,不是一个传说!DevOps,不是一个传说! 7月12,VMware网络云博会,iPhone4S,iPad,XBox360等你拿,点击了解详情 WikiPedia上说:"DevOps是软件开发、运维和质量保证三个部门之间的沟...

c#winform窗体嵌入_weixin_30500663的博客-程序员宅基地

最近开发项目,错误的理解了需求,自己做了个窗体的嵌套,虽然是错误的理解了,但是功能还是实现了,做下标记,需要时可以拿来看看。新建两个窗体Form1和Form2,现在需要将Form2显示到Form1里,我们该怎么办呢?上代码先,一看就明白了,在form 的load方法里加入下面的代码,form2是要显示的子窗体,namespace chuangtiqiantao{ p...

C. Anton and Fairy Tale(codeforces)_H-w-H的博客-程序员宅基地

C. Anton and Fairy Tale问题:一个粮仓,早上存粮,晚上被麻雀偷吃。第一天存入n,n是粮仓的容量,之后每天存入m,如果某天存入的量和剩余的量大于n,那么只能留下n。第一天有一只麻雀偷吃,第二天又两只麻雀偷吃,以此类推。问:到第几天粮仓第一次为空。若n &lt;= m;每天都会把粮仓填满(n),直到第n天,粮仓里的粮食会被n只麻雀第一次吃空。若n &gt; m;直到第m天,粮仓一直是满的–(n),但从m+1天开始,粮仓的粮食每天都会减1,因为你n和m都可能会很大,所以直接爆搜一

Servlet_xdwangiflytek的博客-程序员宅基地

 一、认识Servlet:         Servlet:服务器端小程序,是Java实现的CGI(通用网管接口程序),但是与传统的CGI不同的是,Servlet程序采用的是多线程的处理方式,而传统的CGI是使用多线程的处理方式,所...

随便推点

2021年茶艺师(中级)报名考试及茶艺师(中级)考试技巧_童话小镇(王雅丽)的博客-程序员宅基地

题库来源:安全生产模拟考试一点通公众号小程序安全生产模拟考试一点通:茶艺师(中级)报名考试根据新茶艺师(中级)考试大纲要求,安全生产模拟考试一点通将茶艺师(中级)模拟考试试题进行汇编,组成一套茶艺师(中级)全真模拟考试试题,学员可通过茶艺师(中级)考试技巧全真模拟,进行茶艺师(中级)自测。1、【单选题】泡茶水温的高低,与茶的老嫩、条形松紧有关。茶叶原料粗老、紧实要比细嫩、松散的茶汁浸出要( )得多,所以冲泡水温要( )。(D)A、快、低B、快、高C、慢、低D、慢、高2...

超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务_weixin_34384681的博客-程序员宅基地

Github 地址:https://github.com/Snailclimb/springboot-integration-examples ,欢迎各位 Star。目录:使用 SpringBoot+Dubbo 搭建一个简单分布式服务实战之前,先来看几个重要的概念什么是分布式?什么是 Duboo?Dubbo 架构什么...

softmax_再见鲁鲁修的博客-程序员宅基地

可以参考:https://blog.csdn.net/qian99/article/details/78046329第一篇博客中将损失函数定义为下面的会更加容易理解:将 定义成: 或者: 关于损失函数的求导问题:损失函数的求导目标是 : ...

Java数组_可爱滴老唐的博客-程序员宅基地

总的来说这篇文章比较简单。数组到底和其他的容器有什么不同1.数组是一个线性序列,这使得数组的访问非常的快速,当然数组的灵活性也比不上ArrayList但是实现ArrayList这样的弹性的开销非常的大,所以其速度远远比不上数组。 2.容器使用的泛型导致容器很多时候必须面临运行时检查,但是数组对于类型的检查却总是在编译期。 下面用一段代码来展示一下两者的区别与联系:impor...

Android自定义View-一个可可爱爱的波浪特效_Android架构师丨小熊的博客-程序员宅基地

1. 概述最近开始学习自定义View,看到现在公司项目上的一个动画效果,顿时想到其实可以自己画,于是就开始着手优(zhuang)化(bi)这个动画。动画如下:其实很简单对不对,但初学者的我还是要思考一下。2. 动画分解动画有两部分,第一个是背景,这个直接画bitmap就可以了。 第二个就是这个波浪,我们仔细观察这个波浪其实是一个有规律的,基于每一个点的原点Y轴方向的不...

Go并发原理_weixin_34125592的博客-程序员宅基地

Go语言是为并发而生的语言,Go语言是为数不多的在语言层面实现并发的语言;也正是Go语言的并发特性,吸引了全球无数的开发者。并发(concurrency)和并行(parallellism)并发(concurrency):两个或两个以上的任务在一段时间内被执行。我们不必care这些任务在某一个时间点是否是同时执行,可能同时执行,也可能不是,我们只关心在一段时间内,哪怕是很短的时间(一秒或者两秒...

推荐文章

热门文章

相关标签