前不久小米等六家互联网公司发表联合声明,呼吁运营商打击流量劫持。流量劫持最直观的表现,就是网页上被插入了一些乱七八糟的广告/弹窗之类的内容或者网址被无辜跳转,多了推广尾巴。好比下面这种:html
页面的右下角被插入了广告。android
流量劫持整体来讲属于中间人攻击(Man-in-the-Middle Attack,MITM)的一种,本质上攻击者在通讯两端之间对通讯内容进行嗅探和篡改,以达到插入数据和获取关键信息的目的。目前互联网上发生的流量劫持基本是两种手段来实现的:正则表达式
域名劫持:经过劫持掉域名的DNS解析结果,将HTTP请求劫持到特定IP上,使得客户端和攻击者的服务器创建TCP链接,而非和目标服务器直接链接,这样攻击者就能够对内容进行窃取或篡改。在极端的状况下甚至攻击者可能伪造目标网站页面进行钓鱼攻击。通常而言,用户上网的DNS服务器都是运营商分配的,因此,在这个节点上,运营商能够随心所欲。例如,访问http://jiankang.qq.com/index.html,正常DNS应该返回腾讯的ip,而DNS劫持后,会返回一个运营商的中间服务器ip。访问该服务器会一致性的返回302,让用户浏览器跳转到预处理好的带广告的网页,在该网页中再经过iframe打开用户原来访问的地址。浏览器
HTTP劫持/直接流量修改:在数据通路上对页面进行固定的内容插入,好比广告弹窗等。在这种状况下,虽然客户端和服务器是直接创建的链接,可是数据内容依然可能遭到野蛮破坏。例如在运营商的路由器节点上,设置协议检测,一旦发现是HTTP请求,并且是html类型请求,则拦截处理。后续作法每每分为2种,1种是相似DNS劫持返回302让用户浏览器跳转到另外的地址,还有1种是在服务器返回的HTML数据中插入js或dom节点(广告)。缓存
可以实施流量劫持的根本缘由,是HTTP协议没有办法对通讯对方的身份进行校验以及对数据完整性进行校验。若是能解决这个问题,则流量劫持将没法轻易发生。安全
关于流量劫持的更多危害案例,能够参考:如何看待小米等联合声明:呼吁运营商严格打击流量劫持?服务器
HTTPS,是HTTP over SSL的意思,提到HTTPS就不得不先简单描述一下SSL/TLS协议。SSL协议是Netscape在1995年首次提出的用于解决传输层安全问题的网络协议,其核心是基于公钥密码学理论实现了对服务器身份认证、数据的私密性保护以及对数据完整性的校验等功能。1999年IETF将SSL 3.0标准化,是为TLS 1.0版本,目前TLS协议的最新版本是1.2版本,TLS 1.3标准正在制定中。为了方便,下文将SSL/TLS协议都简称为SSL协议。微信
SSL协议在HTTP请求开始以前增长了握手的阶段,其粗略流程以下图所示:网络
在SSL握手阶段,客户端浏览器会认证服务器的身份,这是经过“证书”来实现的,证书由证书权威(CA)为某个域名签发,能够理解为网站的身份证件,客户端须要对这个证件进行认证,须要肯定该证书是否属于目标网站并确认证书自己是否有效。最后在握手阶段,通讯的双方还会协商出一个用于加密和解密的会话密钥。app
SSL握手阶段结束以后,服务器和客户端使用协商出的会话密钥对交互的数据进行加密/解密操做,对于HTTP协议来讲,就是将HTTP请求和应答通过加密以后再发送到网络上。
因而可知,由于SSL协议提供了对服务器的身份认证,因此DNS劫持致使链接错误服务器的状况将会被发现进而终止链接,最终致使DNS挟持攻击没法实现。此外SSL协议还提供数据的加密和完整性校验,这就解决了关键信息被嗅探以及数据内容被修改的可能。
可是https也不是如此完美,虽然https解决了诸多安全问题,可是对性能也有着比较大的影响。一是用户要从http跳转到https,而且要多几回TLS的握手,这会消耗必定的时间;二是服务器的压力也会增长。除此以外若是使用全站的https,全部页面里面的嵌入资源都要改为https,APP的程序也要进行相应的修改,CDN的全部节点也必须都支持https而且导入证书。因此全站https并非一件容易的事情,国外的Google、Facebook、Twitter早已支持全站https,但目前国内大多数公司都没有采用全站https的方式,微信算是一个,前段时间百度表示已经支持全站的https了,前段时间我试了一下,百度主站在pc端和移动端都已经能够自动跳转到https了,可是近期发现移动端又恢复成http了,多是考虑访问体验问题。因而可知全站https应该是将来互联网的趋势。
让用户不使用运营商的local DNS改用114DNS,114DNS是国内最大的中立缓存DNS。推进用户本身手工去改DNS显然是不可行的,用户10个有9个都不知道DNS是啥。那如何去让用户不使用运营商的local DNS呢?po主在腾讯的一个工程师的博客里面看到有这么一段话:“如何在用户侧构造域名请求:对于PC端的客户端来讲,构造一个标准的DNS请求包并不算什么难事。但在移动端要向一个指定的LocalDNS上发送标准的DNS请求包,并且要兼容各类iOS和android的版本的话,技术上是可行的,只是兼容的成本会很高。”po主认为这种方式暂且不谈技术上是否可行,最大的问题应该是没法确保公共DNS的稳定性。一旦公共的DNS遭到攻击,将会致使全国性的故障,因此必定须要一个冗余的方案,就是当公共DNS挂了后,能够去向运营商的local dns去请求。
这种解决思路,po主了解的有两种方式,第一种是httpdns,这种应该是目前DNS防劫持的主流方式,可是网上相关的介绍很是少,从腾讯员工的博客以及阿里朋友给的内部资料上看,如今腾讯和阿里都在用这种方式。另外一种是网宿的MAA解决方案。二者的原理大同小异,都是为移动APP而量身定制的。
httpdns的原理大体就是在移动客户端中加入一个域名解析的模块,客户端经过http的方式向企业的流量调度服务器请求ip,此时流量调度服务器会回根据用户所在位置给用户一个最优的ip。客户端在获取ip后直接用此ip来访问所需站点资源。
这种方式看着确实很完美,可是对于通常的企业来讲想要实现是一件极具挑战的事情。
一、客户端须要进行必定的开发来知足客户端的httpdns的请求;
二、针对这个流量调度服务器须要本身开发一套全部节点的IP地址库以及测速系统,才能够保证将用户引导的访问最快的IDC节点上,而且对于使用了CDN加速的域名来讲,这个IP地址库是不可控的。
三、如何保证高可用性以及不一样运营商的用户访问到同一个HttpDNS的服务IP,用户的访问延迟?腾讯的作法是:HttpDNS经过接入了腾讯公网交换平台的BGP Anycast网络,与全国多个主流运营商创建了BGP互联,保证了这些运营商的用户可以快速地访问到HttpDNS服务;另外HttpDNS在多个数据中心进行了部署,任意一个节点发生故障时均能无缝切换到备份节点,保证用户解析正常。
因此说httpdns是一个好的解决方案,可是用起来并不容易,而其投入产出比也只有在一些巨型的互联网公司身上才能体现出来。
再来讲说网宿的MAA的解决方案,po主以为和httpdns比较相似,前提是这个域名要使用网宿的CDN加速。网宿的MAA方案其实就是帮通常企业来解决上面httpdns的三点难点。
一、客户端插入网宿研发的SDK,向其鉴权服务器请求ip;
二、网宿的鉴权服务器相似于httpdns中的流量调度服务器,由于CDN厂商原本就要负责调度CDN节点的资源,因此这点对他们来讲很容易;
三、如何保证高可用性以及不一样运营商的用户访问到鉴权的服务器,用户的访问延迟?这点网宿的资料里面没有提到,po主我的猜想问题应该不大,由于对于一个CDN加速的域名来讲,用户原本就是要去网宿的鉴权的服务器的,而对于一个提供CDN服务的厂商来讲,鉴权的服务器的高可用确定是要作好的。
(以上绝对非软文,po主以为是个很好的解决思路,表示要向网宿征收广告费啊!!!)
可是网宿的这个解决方案一样存在问题:
一、插入SDK的方式不少大企业可能没法接受
二、只能用于网宿加速的域名,其余厂商的CDN节点的ip信息网宿不可控,这样可能会被一个厂商绑架。
总的来讲主动防护型的解决方案整体上看虽然能够从根本上解决劫持问题,可是成本高,研发周期长,适合超大的互联网公司,但未必适合全部企业。
被动监测型主要是经过采集用户访问站点的网络参数的方式来判断是否遭到劫持,好比经过采集用户访问站点的ip地址来和咱们真实站点以及CDN节点的ip地址进行比对,判断是否遭到DNS劫持,或者经过采集用户访问的URL和真实站点的URL进行比对,判断是否遭到链路劫持。在PC时代对于被动监测型通常就是真机模拟这一种方式,可是在随着移动互联网的快速发展,针对于移动APP出现了一种插入SDK来监测的方式,这两种方式采用的技术手段彻底不一样,也各有利弊。这种小规模的检测还行,实际应用中,基本仍是以方案 2 为主。
例如这里先对外网作检测,上报被劫持的状况:
window.addEventListener('DOMNodeInserted', checkDivHijack); function checkDivHijack(e) { var html = e ? (e.srcElement.outerHTML || e.srcElement.wholeText) : $('html').html(); var reg = /http:\/\/([^\/]+)\//g; var urlList = html.match(reg); if (!urlList || urlList.length == 0) { return; } reg = /^http:\/\/(.*\.qq\.com|.*\.gtimg\.cn|.*\.qlogo\.cn|.*\.qpic\.cn|.*\.wanggou\.com)\/$/; var hijack = false; for (var i = 0; i < urlList.length; i++) { if (!reg.test(urlList[i])) { hijack = true; break; } } }
(注:过后发现这个url检查不够严谨,虽然劫持的状况都能发现,但也把产品原有的一些正常插入作劫持误报了。例如<a href="http://jiankang.qq.com" data-id="1">,不过这个是小细节,把正则表达式完善一下就ok了)
好比还能够针对注入dom节点的状况,初始化时作检查,并且后续dom注入也作检查。能够检查dom中是否含有白名单之外的http连接,若是有,就能够断定为http劫持。
通常来讲,工程师作低成本的防护须要先找到运营商设置的劫持规律。好比这个 case 中查到是运营商采用 document.write 改写了页面内容或者 dom 节点,那么咱们能够简单粗暴的将document.write重写为空函数:
var oldDocwrite = document.write,newDocwrite = function(str){}; if(oldDocwrite.apply){ hao360.docWrite = function(str){ oldDocwrite.apply(document,arguments); } }else{ hao360.docWrite = oldDocwrite; } document.write = newDocwrite;
显然这种方案有些太不优雅,但却也颇有效。
第二个方案是豆瓣 http://www.douban.com/js/do.js 尾部用到的白名单过滤方案:
// @TODO 临时应对劫持 by dexteryy var _write = _doc.write, _white_list = { 'douban.com': 1, 'douban.fm': 1, 'google.com': 1, 'google-analytics.com': 1, 'googleadservices.com': 1 }, // 统计劫持状况 _hijack_stat = function(reason, env){ var img = new Image(); img.onload = function(){}; img.src = "http://www.douban.com/j/except_report?kind=ra022&reason=" + encodeURIComponent(reason) + "&environment=" + encodeURIComponent(env); }, _RE_SCRIPTS = /<script.*?src\=["']?([^"'\s>]+)/ig, _RE_DOMAIN = /(.+?)\.([^\/]+).+/; _doc.write = function(str){ try { var s, safes = [], unkowns = []; while (s = _RE_SCRIPTS.exec(str)) { if (_white_list[(_RE_DOMAIN.exec(s) || [])[2]]) { safes.push(s); } else { unkowns.push(s); } } if (unkowns.length > 0) { _hijack_stat([unkowns[0], safes[0] || ""].join("~_~"), location.href); } try { _write.call(this, str); } catch (ex) { _write(str); } } catch (ex) { _write(str); _hijack_stat(ex.name + ":" + ex.message, location.href); } };
上两个方案可视项目状况而定,各有利弊。
可是若是运营商换个方案,不采起document.write,那真就要很难斗了。固然若是无耻的DNS劫持始终跟着流量入口页的对策升级方案,那我们仍是洗洗睡吧。
另外说一句一些地方的小运营商,如四川南充某运营商所管辖的这部分地域,直接将hao.360.cn指向本身的导航页面了,虽然样子仍是按期缓存360导航的页面,但其中内容却已被改动多半。对于这些的确的用户反馈,咱们只能表示无奈,且也尝试付诸于法律手段。
因此结论就是运营商是用户的“最后一千米”,咱们只能尽力而为也就是了。
[1] 使用HTTPS防止流量劫持
https://yq.aliyun.com/articles/2666
[2] 关于互联网流量劫持分析及可选的解决方案
http://www.jianshu.com/p/eff9553c8b64#
[3] 关于启用 HTTPS 的一些经验分享(一)
https://imququ.com/post/sth-about-switch-to-https.html
[4] 关于启用 HTTPS 的一些经验分享(二)
https://imququ.com/post/sth-about-switch-to-https-2.html
[5] 运营商DNS劫持的那些事儿 做者:irideas
[6] 【HTTP劫持和DNS劫持】腾讯的实际业务分析
http://www.cnblogs.com/kenkofox/p/4919668.html
[7] 疯狂的淘宝客:一次搜索引擎流量劫持事件分析
[8] dig与dns基本理论——解析和缓存
http://www.juvenxu.com/2014/08/04/dig-and-basic-dns-resolving-and-cache/
[9] 详解https是如何确保安全的?