按照劫持的方法不一样,我将劫持分为下面两类:html
跳转型劫持:用户输入地址A,可是跳转到地址B服务器
注入型劫持:有别于跳转型型劫持,指经过在正常的网页中注入广告代码(js、iframe等),实现页面弹窗提醒或者底部广告等,又分为下面三个小类:cookie
注入js类劫持:在正常页面注入劫持的js代码实现的劫持网络
iframe类劫持:将正常页面嵌入iframe或者页面增长iframe页面测试
篡改页面类劫持:正常页面出现多余的劫持网页标签,致使页面总体大小发生变化网站
为了获取流量,一些电商或者相似百度这样须要流量合做的网站都会有本身的联盟系统,经过给予一些奖励来获取导流,好比:百度或者电商会有渠道分红。ui
为了区分哪些是第三方给予导流过来的,一般会在url地址增长相似source、from之类的参数,或者进入页面以前经过「中间页」种cookie。加密
这样,当用户输入一个正常网址的时候,劫持方会在网络层让其跳转到带分红或者渠道号的「中间页」或者带渠道号的页面。这样用户进行下单或者搜索等行为,劫持方会获得「佣金」。url
上面说的这类case还算友好,至少用户通常体验不到页面变化,还有相似跳转到钓鱼网站的case,也有不正当竞争的case:用户输入baidu.com跳转到so.com或者sm.cn,而对方网站有故意作成和百度搜索差很少的样子,那时候也帮助法务作了不少案例收集。spa
题外话:前些年,用户使用百度搜索某些医疗类query,当即用户就会收到电话推广医院,不少用户投诉,不明真相的群众也指责百度,实际这类是运营商把url的关键词卖给了医疗机构,百度只不过是躺枪。。。那时候还作了个项目是加密query。。。
页面在传输的过程当中,被网络层进行内容「再加工」,常见有:注入js、iframe、篡改页面。
注入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代码,请求不会发到百度的服务器。
这类case比较少见,可是一些擦边球的网站或者没有内容的垃圾站会用这种方式,他们通常是经过热门关键词之类作SEO,打开网站实际去了广告之类没有任何实际内容,而页面倒是内嵌了一个其余网站,咱们要是识别出来不被内嵌就须要检测。
这类case不多见,通常是在页面底部增长js以外的div,而后展示一些非网站内容。
讲了常见的劫持手段有哪些,咱们再来看看怎么识别上面提到的这些劫持。

上图是15年8月11日这天百度某页面的劫持状况,那天数据还算不错,以前浙江移动网络劫持率高达40%+,多数劫持来自 zjtoolbar.10086.cn
这个域名,就是移动的流量提示(还专门启用个域名zjtoolbar,浙江toolbar)。。。
跳转型劫持若是用单纯靠Web页面进行检测比较困难,当时咱们作检测是在手机百度(手百)内作检测,因此比较简单,用户输入搜索词(query),打开百度的页面URL,而后当页面加载结束,APP对比访问的URL是不是以前要访问的URL,若是URL不一致,则记录上报。
改写 document.write
方法
遍历页面 script
标签,给外链js增长白名单,不在白名单内js外链都上报
这个经过比较 parent
对象,若是页面被嵌套,则 parent!==window
,要获取咱们页面的URL地址,可使用下面的代码:
function getParentUrl() {
var url;
if (parent !== window) {
try {
url = parent.location.href;
} catch (e) {
url = document.referrer;
}
}
return url;
}
前面提到相似电信捏造在白名单内的js URL和篡改页面内容的,咱们用上面提到的方法检测不到这些信息,若是是在APP内,能够作的事情就比较多了,除了上面以外,还能够比较页面的 content-length
。当时手百的作法是:
在用户开始输入query的时候,APP访问一个空白页面,页面内只有html、title、head、body、script,而script标签内主要代码就是嗅探是否被劫持。
由于通常劫持不会针对某个页面,而是针对整个网站域名,因此咱们的空白页面也会被劫持。
一旦被劫持,那么这么简单的页面结构就很容易作页面劫持分析,分析出来劫持手段就上报case
script内核心代码以下:
function hiJackSniffer() {
var files = $.toArray(D.querySelectorAll('script[src]'));
var arr = [];
for (var i = 0, len = files.length; i < len; i++) {
files[i].src && arr.push(files[i].src);
}
if (arr.length) {
return sendImg(arr, 1);
}
arr = getParentUrl();
if (arr && arr.length) {
//被嵌入iframe
return sendImg([arr], 2);
}
if (D.documentElement.outerHTML.length > 4e3) {
var tmp = {};
var headjs = $.toArray(D.head.querySelectorAll('script'));
var unknownCode = [];
if (headjs.length) {
unknownCode = unknownCode.concat(headjs.map(function(v) {
return v.innerHTML;
}).filter(function(v) {
return !!v;
}));
}
var body = $.toArray(D.body.querySelectorAll('*'));
if (body.length > 1) {
unknownCode = unknownCode.concat(body.map(function(v) {
return v.outerHTML.split('\n').join('');
}).filter(function(str) {
if (/^<script id="b">/.test(str)) {
return false;
}
return true;
}));
}
return sendImg(unknownCode, 3);
}
sendImg([], 0);
}
这样作除了能够检测到多余的js外链,还能够检测出来篡改页面内容等case。除了检测域名劫持以外,在用户输入query的时刻访问空白的页面也能够提早完成DNS解析,另外还能够作劫持防护,所谓「一石三鸟」!
最简单粗暴的就是直接上 HTTPS
,一劳永逸。再就是取证,去打官司或者警告渠道做弊者。除此以外,咱们还能够继续利用空白页面作劫持检测。
手百在没有全量https时期(毕竟全站https牵扯的工做量不小),利用空白页面嗅探出当前网络环境存在劫持风险的时候,那么就经过调用客户端的接口,告诉客户端本次启动期间使用 https
,这样既能够下降劫持风险,又能够经过这个页面小流量测试https数据,未来https全量后,还能够经过空白页面将老版本的APP全量打开https