JS 代码安全保护
最初原因是有防爬的需求,因此需要对于 web 应用进行安全防护,从最初的数据对称加密(aes) ,到字体混淆(fontmin) ,再到后面的非对称加密(rsa + sm4) ,以及 js 代码混淆(javascript-obfuscator) 。做的越多越是觉得前端所能做其实很有限,以上种种都避不开一个问题,js 最终是要在浏览器运行的并且界面也要响应用户的交互行为的,甚至爬虫不用关心你的底层逻辑,直接执行你的代码即可拿到最终数据, 这个结论无疑是令人沮丧的,但是转念一想不能因为锁能被撬开,就连门都不关了。防爬,准确来说攻防相关是一个循环往复的过程,只能不断提升攻击者的攻破的成本,拦截掉一大部分,非专业人士的爬取。那我们先抛开整个风 控系统不谈,思考一下前端还能做些什么。
代码安全的常见方案
其实最开始的时候,下意识想的防爬其实是怎么不让用户调试代码,方案用的也都是大家日常见到的方案。
-
禁用 devtools
- 最初级的是屏蔽快捷键,屏蔽右键,让用户无法打开 devtool。 先打开 devtool 再打开网页可以破解
- 埋入死循环 debugger,debugger 只有在 devtool 时才会执行,进阶一些检测 debugger 间隔时间。不管怎么变种只要禁用掉 debugger 即可。
- 调用 performance,devtool 打开的时候性能变差,可以大量 console 差异会更加明显。
- 检测窗口变化,使用 mobile 模式可以破解。
- 其他类型,基本都可以原理都要基于 window 上的某些函数或者 API 来实现的,那么加载之前修改 window 对象上方法都可以破解。更多可以参考 disable-devtool 这个库。
-
代码混淆
-
最基础的压缩。最常用的 UglifyJS,Terser,esbuild 等。只是压缩了代码体积,简单的字符串混淆。经过
devtool format 之后具有较强的可读性,调试起来十分方便。 -
基础的混淆,eval 混淆,aa & jj 混淆。此类都是比较有规律的,比如 eval 内部方法的字符串一般使用 base64。aa & jj 就是相似字符作变量名,降低可阅读性。
-
集大成者 javascript-obfuscator 或者类似的 OOLVM 混淆,主要包含了
控制流平坦化、虚假控制流、指令替换,核心是控制流平坦化,简单介绍一下:控制流平坦化

基本块的执行流程,通过控制流平坦化,基本块间的前后关系将被混淆,从而加大了程序逆向分析的难度。逆向的思路基本是使用
符号执行或者AST还原混淆代码 -
WebAssembly, 使用C、C++、C# 、Rust 开发编译为wasm格式的低级类汇编语言,WebAssembly本质上是为提升性能使用等, 一些核心的逻辑可以使用这些语言比如说加解密逻辑。用户只能在浏览器看到二进制数据而无法查看加解密的逻辑,当然只是能提升逆向的难度而已,能编译就能反编译。
-
jsvmp 配合WebAssembly使用
jsvmp 全称
js虚拟化保护(Virtual Machine based code Protection for JavaScript),简单来说就是将代码转换成自定义的字节码,浏览器加载的就是这些字节码,这些字节码只有虚拟解释器才能识别出来。这个方案特殊在
虚拟解释器使用WebAssembly 来实现,使用C语言做解释器,WebAssembly 方案可以隐藏关键的解释器执行逻辑。从本质上来说,上跟上一篇文章的
吾爱破解插入到NeatReader 源码内部的那段代码一致。那段免责声明就是一段无法识别的Unicode(指令编码),只有经过他写的某个函数(解释器),才能计算出这段文本是什么。jsmvp这种方案是将代码也全部指令化了。解释器放入到了wasm文件中。 js代码安全-反编译初试JSVMP的保护流程图

-
参考文献
基于 WebAssembly 的 JavaScript 代码虚拟化保护方法- 匡开园
