1-现像
最近越来越多的用户向客服反映,在使用我们的App过程中,会莫名其妙的在底部出现广告,甚至黄色信息。这些信息不但困扰了用户,影响用户的使用,最关键是使得用户散失对我们公司的信任,觉得我们公司的开发技术不行(什么???什么?技术不行??出来,出来,我要和你大战三百回合、)。那么这个时候不仅仅是要给用户一个合理的解释,查出现象的原因,杜绝现象的再发生就显得迫不及待了。
2-原因
当时接到用户反馈,我们第一时间对现象发生的原因进行了一系列猜想:
1.是不是我们项目中的第三方jar非官方版本,被植入了一些广告代码
2.dns劫持
3.http劫持
做技术的都明白,那就是经验有的时候是助力,也是阻力。很多时候我们会被我们的经验所羁绊。很多资深技术,看到第一条的现象很容易冒出脑海的肯定是:劫持。
那么第一条的理由是不是可能导致这种现象,从实现来说,完全可以做到的。现在很多开发人员平常开发过程随意之极,频繁的在项目使用一些小众且不规范的第三方jar包。而这些第三方jar也会是一些广告的来源。甚至是安全隐患的来源。
另一方面我们根据我们的猜想对用户及时进行了回访,以便验证我们的猜想的正确性。
1.用的是4g还是wifi?
2.如果是wifi,是不是路边免费的wifi?
3.在什么页面出现?(方便定位是h5页面还是原生界面,对大部分用户,千万不要问他是h5还是原生,只能自己分析,如果原生界面也出现那么第三方jar出现问题的概率很大,如果只是h5界面,那么劫持的可能性很大)
4.使用的是android 还是ios客户端
综合用户的答案,我们总结如下:
1.4g,wifi都出现了。
2.出现的位置都是h5页面。
3.android ios都出现了
3-排查
那基本可以定位是网络劫持原因。那么网络劫持有2种
1.dns劫持
2.http劫持
什么是DNS劫持:
首先DNS是什么。在因特网中,机器相互识别靠的是ip,而ip单纯的无意义数字的结合,很难被人类熟记,所以产生了域名,例如www.baidu.com 就是域名。那么问题来了,我们输入域名,机器又不认识,那么机器怎么去访问?那么就轮到DNS出场了,DNS在作为域名和IP地址相互映射的一个分布式数据库,就是我们的浏览器,会将域名拿到DNS去解析出ip地址来访问,DNS劫持是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回假的IP地址或者什么都不做使请求失去响应,其效果就是对特定的网络不能反应或访问的是假网址。
通俗来说,就是他给我们指向了另一个地址,或者让我们无法访问。电信以前的互联星空的,每次联网打开的第一个网页永远是互联星空。就是典型的DNS劫持。
什么是http劫持:
百度百科的说法:HTTP劫持是在使用者与其目的网络服务所建立的专用数据通道中,监视特定数据信息,提示当满足设定的条件时,就会在正常的数据流中插入精心设计的网络数据报文,目的是让用户端程序解释“错误”的数据,并以弹出新窗口的形式在使用者界面展示宣传性广告或者直接显示某网站的内容。
通俗来说,你要去百度的首页,他会给你百度首页,然后再百度首页的某个部位+个广告。 更具欺骗性,危害更大。(毕竟直接给你导向另外一个网址,用户也不是傻逼,上当的可能性很小。)而这也是现在很多免费wifi植入广告的手段,因为这样能更多的点击。
而很明显,我们遇到的是第二种
4-解决方案
原因定位之后,就是制定解决方案了。根据这个http劫持的特性,我们可以很简单的给出解决方案:
https。https是以安全为目标的HTTP通道,简单讲是HTTP的安全版。就是说数据交流是加密的那么所谓的在返回数据里面加点广告就无从谈起了。而且https也能解决dns劫持(基本杜绝)。而https的成本并不高。连某些黄色网站都开始用https。(我擦,不要问我网址)
当时由于距离发版本时间不足2天,而申请https证书要3-4天,那么我们需要一个临时解决方案。那么怎么解决呢。
既然这些猥琐的劫持者通过插入一段js,那么不让他执行这段js就好了。
因为android3.0以后webview提供了方法可以方便的拦截到所有的ajax请求,那么所有的js,图片下载都可以拦截到。我们可以做个区分,对要执行的js做一个筛选。
从API 11开始引入,API 21弃用
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return Tool.getResponse(WebViewActivity.this,url,control);
}
从API 21开始引入
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
return Tool.getResponse(WebViewActivity.this,request.getUrl().toString(),control);
}
webview在WebViewClient里提供的2种拦截ajax请求的方法
所有我们做了白名单和黑名单的机制,因为现在hybird的开发流行,app嵌入了很多h5,而h5页面的制作也参杂了很多第三方的jar,如果只是单纯的把公司域名下的请求之外的请求拦截,很容易导致h5的某些功能无法使用,所有我们采用了拦截开关的机制。在前2天上报非白名单的url,方便我们派出一些误伤的url,这样加入到白名单,以后开启拦截的开关,就能做到无误伤。(https才是正统的解决方案,拦截请求的局限性太大,而且很容易导致功能误伤)。
然后我拿着我开启了拦截开关的app,上了上海的8号线,连上了花生免费wifi,果然---广告都不见了。
贴一些代码。这边一定要注意,拦截的话一定不能返回null,返回null的话,webview回去正常加载
从API 11开始引入,API 21弃用
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
return new WebResourceResponse("text/html", "UTF-8", new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
从API 21开始引入
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
return new WebResourceResponse("text/html", "UTF-8", new InputStream() {
@Override
public int read() throws IOException {
return -1;
}
});
}
5-拓展
中国的网络大环境,http劫持广告很难从源头杜绝。随着越来越多的app嵌入h5,会有越来越多的人在手机端遇到这种劫持广告,作为开发者,一定不要觉得说,这是用户使用免费wifi的原因或者这是运营商的植入广告。我们有的时候改变不了大环境,那么我们做出更多的努力,在app端让劫持广告更难成功。
码农的路上,纵情向前!