js逆向--反爬介绍(1)
一.介绍:
近几年大数据的发展,各个公司的数据保护意识越来越强,随着前端技术的发展,前端代码的打包技术,混淆技术,加密技术层出不穷,使各公司可以在前端对js代码采取一定的保护,比如变量名混淆,执行逻辑混淆,反调试,核心逻辑加密等,使得我们没法轻易地找出js代码中包含的执行逻辑。
对于反爬网站复杂的,没有办法破解就只能用Selenium等工具模拟浏览器,所见及所得。其实还有一种解决方案就是js 逆向代码,找出其中的加密逻辑,这个方案难度很大,但比Selenium等工具爬取的效率会大幅提高。
后面会介绍一些常见的js逆向技巧,包含浏览器工具的使用,Hook技术,AST技术,特殊混淆技术的处理,WebAssembly技术的处理。
1.1 网站加密和混淆技术
1)网站的URL带有一些看不懂的长串加密参数,要抓取就必须懂得这些参数是怎么构造的。比如digikey的分页参数s:
https://www.digikey.cn/zh/products/filter/multiple-conductor-cables/473?s=N4IgrCBcoA5QTAGhDOl5gL6aA
2)网站的Ajax接口时,有的url参数也是加密的,或者request Headers里面也可能带有一些加密的。
以上二者都属于url参数加密。 有的客户端和服务端约定一种接口校验逻辑,客户端在每次请求服务端接口的时候都会附带一个加密sign参数,客户端通过加密算法来构造sign, 服务端会根据约定好的算法和请求的数据对sign进行校验。
加密和编码的算法,如Base64,Hex编码,MD5,AES,DES,RSA等对称或非对称加密。客户端和服务器肯定也都有对应的sdk实现这些算法,如js的CryptoJS,python的hashlib,crypto等等
3)查看网站的js源码,发现很多压缩了或者看不太懂的字符,比如js文件名被编码,文件内容被压缩,变量是单个字符或者一些十六进制的字符。
上面1,2点的参数加密的确是一个不错的解决方案,但还需要将js代码进行压缩、混淆和加密,这样才不会轻易被破解。
现在js混淆的主流实现是javascript-obfuscator和terser这两个库,使得js代码的可读性大大降低。
1.2 javascript混淆
javascript混淆完全是在javascript上面进行的处理,目的就是使的js变得难以阅读和分析,是一种很实用的js保护方案。javascript的混淆技术(通过javascript-obfuscator库)主要有以下几种:
1)变更名混淆:将带有含义的变量名,方法名,常量名随机变为无意义的类乱码字符串,降低代码的可读性,如转成单个字符或十六进制字符串。
#方法名混淆,应该是十六进制 592648: function(e, t) { "use strict"; t.Z = function(e) { return e && e.__esModule ? e : { default: e } } } #方法名混淆, 单个字符串 n: function(e, t) { "use strict"; t.Z = function(e) { return e && e.__esModule ? e : { default: e } } }
2)字符串混淆:将字符串进行MD5或Base64加密存储,便代码中不会出现明文字符串,这样可以避免使用全局搜索字符串的方式定位到入口
3) 控制流平坦化:打乱函数原有代码的执行流程及函数调用关系,使代码逻辑变得混乱无序。
4)无用代码注入: 随机在代码中插入不会被执行到的无用代码,进一步使代码看起来更混乱。
#比如这里有一段代码: const a = function () { console.log("hello world"); }; const b = function () { console.log("nice to meet you"); }; a(); b(); #注入后 const _0x16c18d = function () { if (!![[]]) { console.log("hello world"); } else { console.log("this"); console.log("is"); console.log("dead"); console.log("code"); } }; const _0x1f7292 = function () { if ("xmv2nOdfy2N".charAt(4) !== String.fromCharCode(110)) { console.log("this"); console.log("is"); console.log("dead"); console.log("code"); } else { console.log("nice to meet you"); } }; _0x16c18d(); _0x1f7292();
5)禁用控制台输出
可以使用disableConsoleOutput 来禁用掉 console.log 输出功能,加大调试难度,示例如下:
const code = ` console.log('hello world') `; const options = { disableConsoleOutput: true, };
混淆后,看不到明文的disableConsoleOutput,混淆后的代码,去浏览器控制台执行,会发现没有任何输出,这里实际上就是将console的一此功能禁用了。
6)调试保护
如果在代码多个位置都加入 debugger 这个关键字,或者定义某个逻辑来反复执行 debugger,那就会不断进入断点调试模式,原本的代码无法就无法顺畅地执行了。这个过程可以称为调试保护。
setInterval(() => { debugger; }, 3000);
这样就会干扰到正常的调试流程。
7)域名锁定
通过控制 domainLock 来控制 JavaScript 代码只能在特定域名下运行,这样就可以降低代码被模拟或盗用的风险。
8)特殊编码
另外还有一些特殊的工具包,如使用 aaencode、jjencode、jsfuck 等工具对代码进行混淆和编码。
参考:下面的文献
文献:
崔庆才 Python3 爬虫教程 - JavaScript 网站加密和混淆技术简介