NodeJs 源码保护

        现在 NodeJs 开发 Server 端越来越流行,如果 Server 部署在自己公司的服务器上,那么可以认为环境是相对安全的,不需要做源码保护。但是如果需要在客户方部署,又不希望自己的源码暴露的时候,这个时候就需要源码保护。一般的源码保护方式就是 js 压缩/混淆之类的操作,增加 js 代码的不可读性,或者说是增加破解难度。

        本文讨论另一种使用字节码编译 nodejs 代码来保护源码的方式。

        NodeJs 使用 google 的 V8 引擎进行编译,具体可以参考  https://zhuanlan.zhihu.com/p/28590489,同时,我们利用 bytenode 这个插件来辅助生成字节码文件,具体请参考 https://github.com/OsamaAbbas/bytenode

        项目构成:使用 express 创建一个项目,项目目录如下:

        

        主要文件及说明:

        bin/www:程序主入口

        routes/:路由 js 文件

        services/:核心业务逻辑处理的 js 文件

        app.js:NodeJs Server 启动入口。

        compile.js:字节码编译 js 的文件,后面会讲到。

        其余的文件不重要,也不会被编译成字节码。

        核心思路就是将关键的 js 代码编译成字节码,以保护我们的业务处理逻辑或者算法。

1. 安装依赖

npm install bytenode --save

2. compile.js,主要逻辑就是将项目代码拷贝到 dist 目录中,遍历 dist 下 routes 和 services 等核心 js 文件目录,使用 bytenode 插件将所有的 js 转换成 jsc 字节码文件,然后删除 js 源文件。

var bytenode = require('bytenode');
var fs = require('fs');
var path = require("path");

fs.exists('./dist', exist => {
    if (exist) {
        delDir('./dist');
    }
    fs.mkdirSync('./dist');
})

// 拷贝目录到 dist 下
fs.readdir('./', (err, files) => {
    if (err) {
        console.error(err);
        return;
    }
    for (var i = 0; i < files.length; i++) {
        var stat = fs.statSync('./' + files[i]);
        if (stat.isFile()) {
            if (files[i].indexOf('compile.js') == -1) {
                fs.writeFileSync('./dist/' + files[i], fs.readFileSync('./' + files[i]));
            }
        } else if (stat.isDirectory() && files[i].indexOf('dist') == -1) {
            createDocs('./' + files[i], './dist/' + files[i], function () {

            })
        } else {

        }
    }

    compileFile()
})

function compileFile() {
    // 编译 app.js 为字节码
    bytenode.compileFile({
        filename: './dist/app.js'
    });
    fs.unlinkSync('./dist/app.js');

    // 编译 filters/routes/services 目录下的js文件为字节码
    compileDir('./dist/filters');
    compileDir('./dist/routes');
    compileDir('./dist/services');
}

function compileDir(dir) {
    var stat = fs.statSync(dir);
    if (stat.isFile() && dir.indexOf('.js') != -1) {
        // 文件,直接转换
        bytenode.compileFile({
            filename: dir
        });
        fs.unlinkSync(dir);
    } else if (stat.isDirectory()) {
        // 目录,列出文件列表,循环处理
        var files = fs.readdirSync(dir);
        for (var i = 0; i < files.length; i++) {
            var file = dir + '/' + files[i];
            compileDir(file);
        }
    } else {

    }
}

//递归创建目录 同步方法  
function mkdirsSync(dirname) {
    if (fs.existsSync(dirname)) {
        return true;
    } else {
        if (mkdirsSync(path.dirname(dirname))) {
            console.log("mkdirsSync = " + dirname);
            fs.mkdirSync(dirname);
            return true;
        }
    }
}

function _copy(src, dist) {
    var paths = fs.readdirSync(src)
    paths.forEach(function (p) {
        var _src = src + '/' + p;
        var _dist = dist + '/' + p;
        var stat = fs.statSync(_src)
        if (stat.isFile()) {// 判断是文件还是目录
            fs.writeFileSync(_dist, fs.readFileSync(_src));
        } else if (stat.isDirectory()) {
            copyDir(_src, _dist)// 当是目录是,递归复制
        }
    })
}

/*
 * 复制目录、子目录,及其中的文件
 * @param src {String} 要复制的目录
 * @param dist {String} 复制到目标目录
 */
function copyDir(src, dist) {
    var b = fs.existsSync(dist)
    console.log("dist = " + dist)
    if (!b) {
        console.log("mk dist = ", dist)
        mkdirsSync(dist);//创建目录
    }
    console.log("_copy start")
    _copy(src, dist);
}

function createDocs(src, dist, callback) {
    console.log("createDocs...")
    copyDir(src, dist);
    console.log("copyDir finish exec callback")
    if (callback) {
        callback();
    }
}

function delDir(path) {
    let files = [];
    if (fs.existsSync(path)) {
        files = fs.readdirSync(path);
        files.forEach((file, index) => {
            let curPath = path + "/" + file;
            if (fs.statSync(curPath).isDirectory()) {
                delDir(curPath); //递归删除文件夹
            } else {
                fs.unlinkSync(curPath); //删除文件
            }
        });
        fs.rmdirSync(path);
    }
}

3. 修改 bin/www 文件,在最开始 引入 bytenode

require('bytenode');
var app = require('../app');
var debug = require('debug')('esreader-server:server');
var http = require('http');

...

4. 执行指令打包编译。

node compile.js

编译完成之后, dist 下面的所有文件即可作为发布到第三方服务器上的server。

这样做完之后,项目的启动,或者使用诸如 pm2 等工具来管理 server 时,都与之前的固有做法一致,不需要特殊处理。

 

 

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在Linux下安装Node.js源码有多种方法。其中一种方法是通过建立软连接来使其可以在全局被访问到。首先,你需要使用以下命令建立软连接: ``` ln -s (自己存放nodejs的路径)nodejs/bin/node /usr/local/bin/ ln -s (自己存放nodejs的路径)nodejs/bin/npm /usr/local/bin/ ``` 这样就可以将Node.js的可执行文件和npm命令链接到/usr/local/bin/目录下,使其可以在全局被访问到。\[1\] 另一种方法是通过编译Node.js源码来安装Node.js。然而,在编译过程中可能会遇到各种编译错误问题,很难解决。因此,这种方法并不推荐。\[2\] 还有一种方式是使用包管理器来安装Node.js,比如使用yum install node或者apt-get install node命令来安装。但是需要注意的是,在Linux下默认源中可能没有最新版的Node.js程序,因此这种方式可能安装的是不是最新版的Node.js。\[3\] #### 引用[.reference_title] - *1* *2* [Linux服务器安装NodeJs简易方法](https://blog.csdn.net/weixin_44248258/article/details/124054432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [linux下安装nodejs的方式](https://blog.csdn.net/u011296285/article/details/128370859)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值