NodeJS生成字节码
相关问题:
1.nodejs源码保护
2.nodejs源码加密
3.nodejs提升运行速度
前言
传统的后端运行环境,如 Java、.NET,其源代码是经过编译才部署到服务器上运行的,不存在泄露的风险。而对于应用越来越广泛的 Node.js 而言,运行的则是源代码。即使经过压缩混淆,也可以很大程度地还原。
本文介绍一种可用于 Node.js 端的代码保护方案,使得 Node.js 项目也可以放心地进行私有化部署。
1.原理
当 V8 编译 JavaScript 代码时,解析器将生成一个抽象语法树,进一步生成字节码。Node.js 有一个叫做 vm 的内置模块,创建 vm.Script 的实例时,只要在构造函数中传入 produceCachedData 属性,并设为 true,就可以获取对应代码的字节码。例如:
const vm = require('vm');
const CODE = 'console.log("Hello world");'; // 源代码
const script = new vm.Script(CODE, {produceCachedData: true
});
const bytecodeBuffer = script.cachedData; // 字节码
并且,这段字节码可以脱离源代码运行:
const anotherScript = new vm.Script(' '.repeat(CODE.length), {cachedData: bytecodeBuffer
});
anotherScript.runInThisContext(); // 'Hello world'
这段代码看起来不那么容易理解,主要体现在创建 vm.Script 实例时传入的第一个参数:
- 既然源代码的字节码已经在 bytecodeBuffer 中,为何还要传入第一个参数?
- 为何传入与源代码长度相同的空格?
首先,创建 vm.Script 实例时,V8 会检查字节码(cachedData)是否与源代码(第一个参数传入的代码)匹配,所以第一个参数不能省略。其次,这个检查非常简单,它只会对比代码长度是否一致,所以只要使用与源代码长度相同的空格,就可以“欺骗”这个检查。
字节码计算长度代码如下:
const length = lengthBytes.reduce((sum, number, power) => {return sum += number * Math.pow(256, power);
}, 0); // 27
此外,还有一种更简单的方法:
const length = bytecodeBuffer.readIntLE(8, 4); // 27
综上所述,运行字节码的代码可以优化为:
const length = bytecodeBuffer.readIntLE(8, 4);
const anotherScript = new vm.Script(' '.repeat(length), {cachedData: bytecodeBuffer
});
anotherScript.runInThisContext();
2.字节码的问题
虽然编译成字节码后可以保护源代码,但字节码也会存在一些问题:
JavaScript 源代码可以在任何平台的 Node.js 环境中运行,但字节码是平台相关的,在何种平台下编译,就只能在何种平台下运行(比如在 Windows 下编译的字节码不能在 macOS 下运行)。
修改源代码后要再次编译为字节码,较为繁琐。对于一些如数据库服务器地址、端口号等配置信息,建议不要编译成字节码,仍使用源文件运行,方便随时修改。
本文链接:https://my.lmcjl.com/post/1812.html
4 评论