如何应对ISP乱插广告(案例分析)
一、广告从何而来?
利益让人铤而走险,从而推动行业“发展”;广告的利益还真不小,xx房产门户网站上一个广告位少则几千,多则几十万;记得在校读书的时候,刚学会做网站,第一想法就是等自己的网站发展成熟有人气之后,去接广告放在上面,以此获取收益,后来确实也这样做了,可是结局没有想象的那么美好,就当收获了那份最初的努力吧,会做网站之后亲身经历了房产门户网广告带来的效益,看到管理员发布了满屏的广告,开发网站的我瞬间石化了,他一个DIV(广告位),就可以让他坐享收益,谁让别人是门户网呢,你情我愿,充满商机。
以上这种插入自己广告的网站都还好,而我们身边无处不在的ISP(网络运营商)通过dns、http劫持、重写网络包强行在别人网站插入广告,对于无知的用户来讲他们反而觉得当前这个网站真垃圾,这么多广告,看似就是该网站的恶作剧一样,殊不知网站运营者根本不知道自己的网站被强行植入广告,因为ISP分不同地域、不同宽带用户、不同域名等条件来特定植入广告(我靠猜的,算法要问电信流氓才晓得)。
二、针对ISP乱插广告的感受
话说你ISP在我网站插入广告我都原谅你,可是你别整出问题来啊,网站本身的公共方法被它重写、插入的广告代码有浏览器兼容性、插入的广告直接导致用户白屏(花了半天时间刚填写好发货单,点击某个按钮,发生脚本请求之后,界面什么都看不到了,录单的半天时间就被它无情的剥夺了)
作为网站开发者的我对这种行为感到震惊,因为他们强行在我网站上插播的广告根本没有经过我的认可,从法律角度考虑这种行为同样会有侵犯版权、产生非法收益、危及用户隐私和网站安全等。fuck isp
三、案例一:我网站的日期转换函数被植入的广告代码重写导致客户端所有使用该函数的日期都是错误的
1、先说问题
时隔几个月,没有详细截图,只能口述。
开发a组的同事收到部分用户反馈网站日期不正确,本地测试无论如何都不能重现问题,请注意:是部分客户、测试无论如何都不能重现问题;
开发a组找到平台开发人员,接触新问题一开始都不知道原因,有时候经验也不管用,先分析问题吧:这个问题具有特定性,也就是个体差异,应该从客户端去找原因,并排除假想者认为是服务器数据故障。
2、处理经过
用户在异地,只有通过远程查找问题,已经是很普及的方法了,就连亲戚朋友电脑出问题他们也懂远程协助。
a、确认问题是否存在.
b、既然是javascript函数解析日期出了问题,毫不犹豫按F12快捷键,凭肉眼死盯着界面是看不出问题,必须定位到问题根源。
1、熟悉平台的人凭经验判断找出日期转换函数的位置:输入Date.format,查找定位脚本,设置断点;
2、不熟悉平台的同事,可以根据控件名称来定位脚本,比如界面上很明显的是Grid的DateTimeColumn列日期显示异常,因此在按F12弹出开发人员工具查询框里面输入:DateTimeColumn,定位到对应控件脚本,javascript对程序员来说都不会陌生,凭经验找出日期转换的代码,并设置断点;如下图
c、断点设置好之后,重新打开网页,进入断点,按F11跟进去Date.dateTimeToStr,很明显是自定义的公共函数,继续跟,如下图:
我们知道Date对象是没有format方法的,因此可以判断上面的dateTime.format是平台定义的日期转换函数, Date.prototype.format = function Date$format(format) { …. }, 继续F11。
d、惊奇的事情出现了,当前断点跳入了一个未知的js脚本里面,跟进去的format函数不是平台定义的,意思是:根本没有执行平台format函数而是执行了其他脚本的format。
e、我也是第一次遇到这样的问题,所以说解决问题也是学习的有效途径。 如此一来就会想到,其他脚本从何而来? 才会想到使用网络抓包工具可以看个究竟,就会情不自禁的打开Fiddler,当然还有很多其他工具,第一次接触它就觉得很好用;
为什么要会用Fiddler? 很多开发上遇到问题都可以用这个工具排查,比如调用xx网站的API,首先你要分析它的数据包格式吧。
客户机器肯定是没有该工具的,需要开发人员先安装。
其实F12开发人员工具也可以看到网络请求,看到请求加载的脚本,各大主流浏览器都集成了类似插件。
f、打开Fiddler,刷新网页,可以看到Fiddler里面每一个请求结果,其中就会找到不属于我们网站的脚本,而且很多第三方的脚本请求。
最重要的是用fiddler可以看到服务器返回的json数据,其中日期数据明明就是2014-11-11,页面上显示的日期却是1990,由此可以断定不是服务器数据问题…
3、问题分析
由2,就解释了我们的网站被嵌入了三方脚本,且三方脚本与平台的日期接口函数重名,从而日期转换格式异常。
访问我们的网站为何会嵌入三方脚本?首先想到的是不是哪个开发人员想用第三方js库引入的呢?经过询问排除此原因,如果是程序本身嵌入了第三方脚本,所有客户都会受影响,现在是特定用户。
也不去管js从何而来了,反正程序本身没有,只知道是在网络传输过程中被加入的,从而想到曾经有位老大跟我们说过类似电信广告问题,不过针对此问题改程序本身就有点捉急,改了也不会立刻发版,你懂的,线上几十万用户等着使用呢。
我们分析,嵌入的4个三方js的地址格式,如:http://xxx.com/js/a.js?xxx=xx
在网页中,查看源码表现形式如下:
1 <html> 2 <head> 3 ... 4 </head> 5 <body> 6 7 .... 8 9 <script src = "wsgjp.com/js/carpa.js"/><!--我们网站的js--!> 10 <script src = "xxx.com/js/a.js?xx=xx"/><!--三方js--!> 11 <script src = "xxx.com/js/b.js?xx=xx"/> 12 </body> 13 </html>
有人想到修改用户的hosts文件,将xxx.com 映射到 127.0.0.1,这样特定js的请求会失败,脚本就不会得到执行,因而保全了平台的完整性;查了下,也确实有人这么做的。
问题暂告一段落…
4、就此问题的终极解决方案(比谁更狠)
过一段时间,出现该问题的用户数在递增,不可能挨着去修改用户的hosts文件吧,问题变得扑簌迷离。
方案1:网页加载完毕,程序在客户端(javascript)检测当前网页是否被嵌入了第三方脚本,如果是弹出提示并强制刷新,按理说isp不是每次请求都植入广告的。
方案1施行前做了一个实验,手动刷新客户端网页,用fiddler抓包看,每次刷新都被植入了三方脚本,也就是说方案1会导致客户端不断的弹出提示或一直刷新,就此问题跟听说的不太一样,TMD太狠了,难不成要赶尽杀绝。
方案2:收拾不了它,只有退一步改变自身,让自己变得与别人不一样。重新定义平台的Date.format函数,修改为Date._format,平台引用该函数的一共有4个地方,产品业务几乎没有被使用,很容易做到重构。
好了,虽然不知道是谁干的,也没去分析被植入脚本到底干个啥? 没有发现其他新的问题,仅针对该问题得到了解决。
四、案例二:我网站的特定用户在录单过程中出现白屏
时隔几月,与案例一的经验没有联想在一起,也走了不少弯路才找到问题原因,现象不一样,本质却一样;
开发反馈:某个用户操作过程中白屏了,且出现Type未定义的脚本错误
还得从一开始的问题反馈到远程客户找原因,这个流程是必然的,你需要学会与客户有效且愉快的沟通,不要问题没解决好自己被气的半死,为何要说“气”,曾见过被用户折腾的想哭的客服,对于客户来说你需要转变角色,这点很重要。
问题分析:Type是我们平台的一个公对象,居然出现未定义?焦点一下转移到平台脚本上面去了,是不是平台相关依赖的脚本没有加载?什么情况下没加载?肯定是客户网络慢,开始胡思乱想。
特定客户问题分析要领:从浏览器兼容性、木马病毒(没遇到过)、客户网络几个原因着手。
1、重现问题
告诉用户,让他操作先重现问题;作为平台维护的人,面对不是自己开发的产品和业务流程陌生感油然而生,不过这不是影响解决问题的因素,客户端问题本质是脚本与兼容性,与懂不懂业务没多大关系。
我盯着屏幕,看着用户操作半天,问题依然没出现,好,请他先暂停一下,看来该问题具有偶然性,不是必然重现。
再次分析可能原因:1、与数据有关,特定账号、特定数据才会触发,90%以上是业务性问题。2、特定浏览器下。
是同一账号,数据相同,排除1;客户机器就只有一款ie8浏览器,排除2;
遇到不明原因的问题就越想弄清楚才罢休,开发经验有限,主要还是没有重现问题,不知道具体现象,远程操作紧到找不到原因也耽搁双方时间,就告知客户如果再次出现白屏,保留现场并立刻通知我们。
虽然没重现到问题,还是记录了客户使用情况:windows xp系统、2G内存、IE8浏览器,改为了非兼容模式,问题没有重现;并记录到Tower项目管理计划中:2014-11-04 远程检查,有个客户使用“管家婆快速登录工具”或兼容模式,IE8,特定操作出现白屏的问题(没重现到,特此备案)
2、紧急召回
客户弹窗说他又出现白屏了,远程一看,果然整个浏览器都白茫茫一片,客户还在抱怨花了半天时间录单的事,不厌其烦的开始我的工作,先抓图。
原来客户使用的是自定义的浏览器工具下出现的白屏,排除是否工具问题导致,切换成360安全浏览器试试。如下图,问题一样,说明跟浏览器无关。
好,通过查看源文件,白屏和出现Type未定义错误的现象就很好理解了,整个网页就只剩下两个script标签,所以白屏;其中一个是我们非常熟悉的wsgjp../R.axd?PtypeBarcodeList.js,这个脚本里面对Type对象有引用,而当前上下文紧有两个脚本标签,没有Type对象;之前完整显示的单据中肯定会有table,div,body标签啊,那其他标签去哪儿了?既然问题重现了,那好办多了,管它三七二十一,安装Fiddler,打开Fiddler,操作网页单据,等待问题重现,如下图,铁证如山:
我们wsgjp的网页本身是请求的这个脚本文件,但我们文件的内容绝对不是document.write打头的,可以肯定我们请求的数据包被改写了,至于为什么被改写,什么条件下会被改写,改写结果以后会是什么样,这个还真不好下定论。再仔细看,改写的数据里面多了一个未知域名的脚本,拷贝出来访问,是一个无效的广告链接(电信你这样也可以骗广告费啊,过期的广告请不要乱插)。已经找到白屏原因,导致白屏的罪魁祸首是这句document.write,这也是isp的终极大招了吧,不能在狠了,isp还算有点人性哈,它给我们保留了原始脚本的请求,保证网站业务不会出错,网页不报错,客户就没反馈,我们也就不知道,他就不会留下把柄。
3、问题分析,document.write为何会导致白屏?
案例一如果也是跟案例二一样使用document.write语句植入脚本,但案例一不会有白屏,为什么这么说呢? isp还是考虑了开发人员的感受,他们也不是故意的搞出问题被投诉,虽然投诉没用。
关键问题在于案例二中的document.write语句,先看看document.write语句的作用吧。
document.write()方法可以用在两个方面:页面载入过程中用实时脚本创建页面内容,以及用延时脚本创建本窗口或新窗口的内容。该方法需要一个字符串参数,它是写到窗口或框架中的HTML内容。这些字符串参数可以是变量或值为字符串的表达式,写入的内容常常包括HTML标记语言。
记住,在载入页面后,浏览器输出流自动关闭。在此之后,任何一个对当前页面进行操作的document.write()方法将打开—个新的输出流,它将清除当前页面内容(包括源文档的任何变量或值)。因此,假如希望用脚本生成的HTML替换当前页面,就必须把HTML内容连接起来赋给一个变量,使用一个document.write()方法完成写操作。
针对wsgjp的单据页面,我们在来整理一遍思路,用图说明。
请求1中如果isp对脚本进行了document.write语句修改,只要脚本没冲突就不会有影响,当然广告会成功植入(对产品本身没影响)。因为第一次请求网页没有加载完的过程中使用document.write语句浏览器不会清空当前文档流。
然而请求2中就不是这样了,由于是异步请求,当前网页已经显示完毕,并且用户录入了大量单据和其他操作,当异步请求完毕,平台对返回的脚本使用了eval(慎用),没有过滤检查,直接执行了“服务器”返回的脚本,其中的document.write就是告诉浏览器要清除当前文档所有内容,最后就是我们看到的白屏效果。
4、解决方案
面对如此大招,1、加映射无济于事,这样的情况只有把wsgjp映射到127.0.0.1。 2、检测到有脚本植入,立刻刷新页面,那悲剧了,用户的输入的单据怎么办?当前操作还没保存。
还是得从程序自身出发,eval脚本之前,对脚本进行检查过滤,具体实现细节:
a.检查执行的代码是否对程序本身有干扰,目前就document.write造成白屏影响而谈。
b.如果没有干扰,执行脚本。
c.检测到干扰,也不用去做过滤了,重新请求原脚本文件,既然是异步的那就可以重新请求一遍,轮询a,每个脚本文件出现错误最多尝试8次请求,如果还是被植入广告,那就终止当前用户操作,提示用户,先保存当前任务,过会再试。
d.如果c检测到干扰,记录错误日志到服务器(carpalog.txt),可以作为后续分析统计情况。
五、Fiddler相关推荐
1、Fiddler介绍篇 http://www.2cto.com/kf/201308/234826.html
2、使用Fiddler提高前端工作效率 http://www.2cto.com/kf/201308/234828.html
六、总结
1、ISP拦截请求插入广告
方式一:纂改网页数据包,针对Content-Type为text/html类型的请求,嵌入script标签。
方式二:纂改脚本请求数据包,针对Content-Type为application/x-javascript,完全重写脚本内容,加入document.write语句。
方式三:串改数据包,针对Content-Type为application/x-javascript,完全重写脚本,在原有数据的基础上增加自己的广告代码。
目前就知道以上三种方式,共同的特点广告代码都是外链;其中1、2我们已经遇到过,它没有影响产品的原有结构, 并且我们有相应的对策;3影响了产品的独立性和完整性,已经改变了网站自身的结构了(没遇到过)
七、深究
研究isp广告脚本有何意义?
个人理解不同的广告商植入的广告千奇百怪,层出不穷, 输出到客户端的脚本无非就是一些dom操作,实现广告播放吧;更狠点的盗取客户端cookie信息等;ISP真正有意义的算法分布在不同地方的服务器上。
案例二中为何在地址栏输入http://js.szzhengan.com/re/re.php?…返回内容为空?
那通过我们的电脑访问wsgjp的网站一切正常呢;或许跟我们申请的宽带账号有关系,分区域、特定网络、甚至特定宽带id、按ip归宿地来固定投放广告,总之这是一套复杂的算法。
另外re.php是一个动态文件,中间不知道它要经过多少跳转,整个过程做了些什么事情,这个问题现在还没搞清楚,待牛人出现。。。