关于 node.js 混淆,有没有办法? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kurtis
V2EX    Node.js

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

  •  
  •   kurtis 2014-06-17 09:06:28 +08:00 15598 次点击
    这是一个创建于 4210 天前的主题,其中的信息可能已经有所发展或是发生改变。
    请教各位牛人,一个问题 有没有较好的方案可以混淆 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     Solana     847 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 21:54 PVG 05:54 LAX 13:54 JFK 16:54
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86