V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kurtis
V2EX  ›  Node.js

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

  •  
  •   kurtis · 2014-06-17 09:06:28 +08:00 · 14830 次点击
    这是一个创建于 3817 天前的主题,其中的信息可能已经有所发展或是发生改变。
    请教各位牛人,一个问题 有没有较好的方案可以混淆 node.js程序。

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

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

    感谢先!!!
    27 条回复    2016-01-22 03:22:41 +08:00
    iwege
        1
    iwege  
       2014-06-17 09:09:26 +08:00   ❤️ 1
    貌似有编译成为native module的选项。

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

    require("YourCode.jse");
    liuyanghejerry
        19
    liuyanghejerry  
       2014-06-22 22:29:00 +08:00
    降低可读性不是很容易嘛,只要把注释去掉就行了
    liuyanghejerry
        20
    liuyanghejerry  
       2014-06-22 22:35:00 +08:00
    代码可以用AST工具转成AST,或者其它你能想到的任何代码混淆、加密方式进行变换,然后另存下来,require自己的模块的时候把require封装一下,变为require_x,require别人的包的不要变。在新的require_x函数当中还原代码,再执行真正的require。
    liuyanghejerry
        21
    liuyanghejerry  
       2014-06-22 22:52:12 +08:00
    // 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
       2014-06-23 07:00:49 +08:00
    @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  
       2014-06-23 17:09:56 +08:00   ❤️ 1
    @kurtis var a= require_x("./lib/A.xxx", priviate_key);
    kurtis
        24
    kurtis  
    OP
       2014-06-23 17:26:21 +08:00
    @liuyanghejerry
    首先感谢已发送,很好的集思广益的设想,

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

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

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

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

    ```
    Function.prototype.toString = function () { return "[protect code]"; }
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3474 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 10:50 · PVG 18:50 · LAX 02:50 · JFK 05:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.