混淆、编译 Node.js 源代码的几种方法
思路是这样的:经过保护的代码要能正常运行(当然,不能运行的代码有什么用),同时还不能让别人轻易地看到源码。简而言之,让机器能读懂,而人难以读懂就行了。
# 加密
我们可以对js代码进行加密,每次执行前进行解密,实际运行的是解密后的代码。但是加密对执行效率会有影响,而且一旦密码被破解,源码也就泄露了。
# 混淆
对代码进行混淆,尽量地让代码变得不可读,据说这个思路是从代码写得很差的程序员身上学来的。常见的做法有:分离常量、打乱控制流、增加无意义代码、域名锁定、混淆字符串,禁用调试等方法。
- javascript-obfuscator (opens new window):一个强大的JS混淆器。
- jshaman (opens new window):一套JS代码安全问题解决方案。
# 编译
Node.js代码是通过V8引擎来执行的,而V8引擎会将源代码编译成字节码(bytenode)之后再解释执行。如果我们能将Node.js代码编译成字节码, 将会进一步提高代码的安全性。毕竟反编译V8的字节码并非易事。
- bytenode (opens new window):一个极简的Node.js字节码编译器。
# 打包
把Node.js代码和依赖,打包成一个可执行文件。这样可以增加一点破解的难度。
- ncc (opens new window):可以把Node.js项目打包成一个js单文件,支持 TypeScript,动态导入。
- pkg (opens new window): 可以把Node.js项目打包成一个二进制的可执行文件,pkg不支持动态导入,但是会将Node本身一起打包,可以实现在没安装Node.js的环境运行。
- pmq20/node-packer (opens new window): 也能打包成一个二进制的可执行文件,它的优势在于支持各种形式的require, 也支持C++模块。可惜项目已经两年没更新了,只支持到Node.js 8.3.0, 对于更高版本的支持,请移步slee047/node-packer (opens new window)。
# 方案选择
没有绝对的安全可言,以上的方法只能是加大破解的难度。有道是世上无难事只怕有心人,只要有足够的技术和耐心,还是有可能还原出相应的代码。
作为防守方,我们能做是尽可能地多采用一些保护手段。在这里,提供一个JavaScript obfuscator + bytenode + node-packer
的解决方案。
为什么选用node-packer
而不是ncc
,pkg
呢?因为ncc
和pkg
无法处理混淆过的代码。
# 参考案例
假设我们需要保护的是这样的一个项目:
// index.js
console.log("以下是价值上千万的代码:");
var a = 1;
var b = 1;
var c = a + b;
console.log("1 + 1 = " + c)
2
3
4
5
6
首先我们通过npm
安装javascript-obfuscator
和 bytenode
。然后在当前系统下安装node-packer
。
由于node-packer
无法打包由bytenode生成的.jsc
字节码文件,所以需要添加以下文件来导入.jsc
文件
// build.js
require('bytenode');
require('./index-obfuscated.jsc');
2
3
接着将以下指令加到package.json
:
"scripts": {
"obfuscate": "javascript-obfuscator index.js --string-array-encoding rc4",
"bytenode": "bytenode --compile index-obfuscated.js",
"nodec": "nodec build.js --skip-npm-install",
"build": "npm run obfuscate && npm run bytenode && npm run nodec",
}
2
3
4
5
6
复制代码最后运行npm run build
,可以得到一个a.out
(windows
系统下是a.exe
)的可执行文件。运行一下,价值上千万的代码就跑起来了。
此外你会发现项目目录下多了两个文件:index-obfuscated.js
, index-obfuscated.jsc
。它们分别是混淆之后的代码以及字节码文件。javascript-obfuscator
支持多种混淆技术,可能通过查看文档,按照自己的项目需求,调配选用合适的选项。
# 示例代码
https://github.com/iWinston/javascript-code-protection-example (opens new window)
- 01
- Node与GLIBC_2.27不兼容解决方案08-19
- 02
- Git清空本地文件跟踪缓存08-13