好久没有写博客了,不是没有在学习新东西,是最近比较忙,没有总结。
今天聊的话题是防止js篡改。javascript代码和需要编译的代码有一点不同是,网页上会直接请求js文件源码,而编译的语言运行时使用的是编译后的文件。即使这样,很多编译语言(比如java)都会做源码混淆(obfuscation),前端这样的纯文本应用,更需要做点什么保护我们的逻辑代码不被篡改和窥探。
防止js篡改的原理也很简单,就是增加破解的代价。一下源码可以在我的github查看。
注意:我这里说的前端加密,是对浏览器端的js文件加密,不是传输过程中的加密,不涉及hash摘要等
1. 降低可读性
1.1 压缩(compression)
很好理解,就是去掉注释、多于的空格、简化标识符等等。工具很多,YUI Compressor、UglifyJS、Google Closure Compiler等等。
1.2 混淆(obfuscation)
保证不破坏代码执行结果的情况下,让代码变得难以阅读。常用混淆规则:拆分字符串、拆分数组、增加废代码、,压缩其实也有一定混淆功能。本质就是改变输入代码字符串的抽象语法树(AST)的结构。其他工具:v8就是一个,还有mozilla的SpiderMonkey, 知名的esprima,还有uglify;商业混淆服务有:jscramble。
1.3 加密(encryption)
这里的加密指文本可逆编码,是狭义的加密,也就是我们常说的加密啦。这个部分依然是借助一些工具,如: Packer 、bcrypt等等。
2. 代码不放置在JS文件中
将代码放在非js文件中,增加定位难度。这里常用的方式有两种:放置到png中,通过HTML Canvas 2D Context获取二进制数据的特性,可以用图片来存储脚本资源;放置到css文件中,利用content样式可以存放字符串的特性,同样可以。
2.1 png
用png保存js代码,首先需要对png进行编码,然后使用的时候进行解码。借助canvas及base64和二进制编码。
编码
1、字符串转换成ascii码;
2、创建足够存储空间的canvas;
3、将字符填入到像素中(忽略alpha值);
4、获取data url;
canvas.toDataURL(“image/png”);
5、存为png图片。
function encodeUTF8(str) {
return String(str).replace(
/[\u0080-\u07ff]/g,
function(c) {
let cc = c.charCodeAt(0);
return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);
}
).replace(
/[\u0800-\uffff]/g,