kurtis
V2EX  ›  Node.js

关于 node.js 混淆,有没有办法?

  •  
  •   kurtis · Jun 17, 2014 · 15929 views
    This topic created in 4372 days ago, the information mentioned may be changed or developed.
    请教各位牛人,一个问题 有没有较好的方案可以混淆 node.js程序。

    条件:
    1. 不是单个js文件,而是互相require引用的若干个js组成的一个package
    2. 混淆或者大幅降低可读性即可,不需要加密(估计也无法加密)
    3. 不接受 “没有办法” 或者 “为什么要混淆”之类的回答。

    查阅了很多资料,国外也有人在讨论,方法千奇百怪,但几乎没有一个很靠谱的。

    感谢先!!!
    27 replies    2016-01-22 03:22:41 +08:00
    iwege
        1
    iwege  
       Jun 17, 2014   ❤️ 1
    貌似有编译成为native module的选项。

    这是一个比较简单的做法,就是把自己的js code 作为一个字符串,然后等启动之后再注入到context里面。
    andyhu
        2
    andyhu  
       Jun 17, 2014   ❤️ 1
    服务器端的也要混淆吗?我以前做前段的混淆都是用的一个java的jsa,感觉压缩率和混淆程度都不错,兼容性也好。但是这东西也有些问题,我自己下载到本地无法正常运行,只能用那个网页版本的一个一个手动的来混淆
    livelazily
        3
    livelazily  
       Jun 17, 2014   ❤️ 1
    closure compiler 或者 uglifyjs 压缩过后的可读性已经很低啦,
    kurtis
        4
    kurtis  
    OP
       Jun 17, 2014
    @iwege
    @andyhu
    @livelazily
    感谢你们, 可是问题是:

    1. uglifyjs混肴貌似只能针对局域成员,一旦跨引用就不能了。

    2. 我还研究了node的vm模块,缺点是,沙盒配置很复杂,跨require引用时尤其

    3. 还有类似eval的执行(也就是字符串注入执行),缺点是,一旦eval的加密后解密的明文,任何人可以console.log输出。

    4. 一个台湾人写的叫做npk的模块,跨目录require时会有问题

    期待更多的专业建议! 谢谢先!
    rekey
        5
    rekey  
       Jun 17, 2014
    我就看看,我不说话。
    kurtis
        6
    kurtis  
    OP
       Jun 17, 2014
    昨天 那个啥 白搞了30天女友的帖子出来时,跟贴爆火,可是一旦讨论点像样的技术问题时,发现好孤单啊!!
    juzai
        7
    juzai  
       Jun 17, 2014   ❤️ 1
    iwege
        8
    iwege  
       Jun 17, 2014   ❤️ 1
    @kurtis vm模块的context配置起来是很复杂... 执行效率有数据说明不是非常高。

    上次我也是看到npk,不过项目里面没有用,因为不算是纯粹的node环境没有办法直接用。

    我曾经问过一些人,他们说V8需要source code 进行优化。所以只能做一些核心代码的保护,最好的方法,还是用C++做native module,保护核心,其他的非核心的部分用JS。如果你不要source code的话,速度会降低很多。

    Function的话有一种做法就是在某个时间段给函数用bind()方法可以创建一个native function, toString的时候得不到源码。只是这个在浏览器端防不住。
    iwege
        9
    iwege  
       Jun 17, 2014
    @juzai
    @kurtis

    JXcore 这个有看过,如果你可以换平台的话倒是可以考虑一下。
    juzai
        10
    juzai  
       Jun 17, 2014
    @iwege jxcore你用过吗,我也是刚看了这个帖子,去google了哈
    ipconfiger
        11
    ipconfiger  
       Jun 17, 2014
    远程加载模块到本地执行后删掉源码自动删掉源码如何?
    kurtis
        12
    kurtis  
    OP
       Jun 17, 2014
    @juzai 不错的理念,不过是闭源 第3方,万一有坑会死的很惨。
    @iwege 谢谢建议,c++写一个扩展module的确是一个方法,但远不是完美的办法。

    另外 google group上有人建议 开一个VMWARE Virtual APP出来,也是别有新意的,而且可以用于node以外的非源码公开发布。

    还有什么更完美的吗!?
    eas
        13
    eas  
       Jun 17, 2014
    VMWARE Virtual APP, 这个东西,可以直接作为磁盘被mount出来吧
    hayeah
        14
    hayeah  
       Jun 17, 2014
    应该可以用 browerify 把所有相互依赖的 require 集成为一个单一文件,然后再用 uglify 去混淆。

    browserify 会重写一些 nodejs 的全局对象 (e.g. process) 但我记得可以调掉那个功能。
    jiangzhuo
        15
    jiangzhuo  
       Jun 17, 2014
    在雲上部署的話 如果雲支持docker的話 打成docker包。。。
    kurtis
        16
    kurtis  
    OP
       Jun 17, 2014
    @eas 可以使用用bitlock之类的 不登录无法解密的OS功能


    @hayeah 谢谢这个我要研究一下,不过我试过即使打包在一起,uglify也不会混淆 接口方法和属性
    例如下面的例子中: method 这个字眼 不会被混淆, A好像也不会, 是不是uglifyjs 有些参数可以?
    function A() {
    this.method=function() {}
    }

    var a= new A().method();

    @jiangzhuo 残念,不在云上部署,在云上部署的话相对的不太需要混淆或加密。
    eas
        17
    eas  
       Jun 18, 2014 via iPhone
    @kurtis bitblock 不能做没有硬件支持的系统盘加密
    kurtis
        18
    kurtis  
    OP
       Jun 18, 2014
    有人提到的一种方法,但是问题也一样明显

    // register extension
    require.extensions[".jse"] = function (m) {
    m.exports = MyNativeExtension.decrypt(fs.readFileSync(m.filename));
    };

    require("YourCode.jse");
    liuyanghejerry
        19
    liuyanghejerry  
       Jun 22, 2014
    降低可读性不是很容易嘛,只要把注释去掉就行了
    liuyanghejerry
        20
    liuyanghejerry  
       Jun 22, 2014
    代码可以用AST工具转成AST,或者其它你能想到的任何代码混淆、加密方式进行变换,然后另存下来,require自己的模块的时候把require封装一下,变为require_x,require别人的包的不要变。在新的require_x函数当中还原代码,再执行真正的require。
    liuyanghejerry
        21
    liuyanghejerry  
       Jun 22, 2014
    // require_x.js

    var fs = require('fs');

    module.exports = {
    require_x: function (name) {
    var mod = fs.readFileSync(name);
    mod = decode(mod);
    var real_name = 'hack here as you wish';
    var mod_path = save_file_into_one_dir(real_name, mod);
    // now you have the original js module
    // but be sure all deps are installed in that path.
    return require(mod_path);
    },
    transform_x: function (file) {
    // use async read if you want to
    var mod = fs.readFileSync(file);
    mod = encode(mod);
    var transformed_name = 'hack here as you wish';
    var mod_path = save_file_into_one_dir(transformed_name, mod);
    // now you have your transformed js module file
    return true;
    }
    }

    function encode (content) {
    // do your hack here
    return content;
    }

    function decode (content) {
    // do your hack here
    return content;
    }

    function save_file_into_one_dir(name, content) {
    // do your hack here
    return real_path;
    }


    // app.js

    var require_x = require('./require_x.js');
    var my_mod = require_x('./my_mod_x.js');
    var other_mod = require('other_mod');

    my_mod.use.what.you.have();
    kurtis
        22
    kurtis  
    OP
       Jun 23, 2014
    @liuyanghejerry

    var a= require_x("./lib/A.xxx");

    // insert hack code here
    console.log(a.toString()); // source will be shown here without any encryption
    liuyanghejerry
        23
    liuyanghejerry  
       Jun 23, 2014   ❤️ 1
    @kurtis var a= require_x("./lib/A.xxx", priviate_key);
    kurtis
        24
    kurtis  
    OP
       Jun 23, 2014
    @liuyanghejerry
    首先感谢已发送,很好的集思广益的设想,

    但是我困惑的是加不加privatekey有区别吗?
    反正,都是要decode以后再require。
    任何人只要 加一句console.log 就能看到源码明文。

    var a= require_x("./lib/A.xxx", priviate_key);
    console.log(a.toString());
    liuyanghejerry
        25
    liuyanghejerry  
       Jun 24, 2014
    @kurtis 这只是个框架啊,之后的细节你可以自己根据你实际情况改动。我这个方案的意图是告诉你,可以在require之前做手脚,node拿到的代码是decode过的这一点毫无疑问,因为node的源码没有改动。

    比如decode之后的源码你可以从磁盘上删去,priviate_key你也可以删掉,这些都可以根据你自己的环境做适应啊
    kurtis
        26
    kurtis  
    OP
       Jun 24, 2014
    @liuyanghejerry
    让我想起了google group 里的讨论,里面有个更高级的办法,decode部分都不是用node写的,而是C写的node扩展。 可是破解也是一样的简单,如上所述。因为无论你怎么加密,最终node运行的都是明文,node的机制就是会保留 source 供toString() 使用。任何人都可以自己加上.toString()看到明文。

    关于这一点,@juzai 提到的jxcore 就充分注意到了这个问题,并进行了内核上的改进。
    idoldog
        27
    idoldog  
       Jan 22, 2016   ❤️ 1
    @kurtis 可以尝试一下

    ```
    Function.prototype.toString = function () { return "[protect code]"; }
    ```
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3020 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 58ms · UTC 06:19 · PVG 14:19 · LAX 23:19 · JFK 02:19
    ♥ Do have faith in what you're doing.