nodejs如何进行源码加密

本文探讨了在Node.js环境中如何提高代码安全性,通过混淆、压缩、自定义加密解密等方法来保护源码,详细介绍了不同级别的加密策略及其优缺点,提供了修改Node.js源码实现解密执行的思路。

一、背景

nodejs作为越发繁荣的生态,出现诸多丰富的组件,但是由于nodejs的解释性运行的问题,导致代码安全性的问题越来越大。那么如何对源码进行加密呢,我们通过循序渐进的方法实现代码的加密。

二、解决思路

1.通过代码混淆或者代码压缩,降低可读性。

这类方法普遍使用在github等开源社区中,代码虽然开源,但是只要我不提供文档说明,我不告诉你业务逻辑。给你代码也是瞎的,但是如果对于业务逻辑比较简单的情况,或者有UI功能进行辅助,大家也可以猜个八九不离十。根本谈不上加密,只是增加你修改的难度,本质等同于我不告诉你怎么写的,我不换行写,我所有变量都都用abc定义,你行你自己看呗状态, 个人觉得效果不佳。

加密效果:☆

维护难度:☆☆☆

加密出来的样子:

       t.exports = function() {
            "use strict";
            var t = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) {
                return typeof t
            }
            : function(t) {
                return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
            }
              , e = function(t, e) {
                if (!(t instanceof e))
                    throw new TypeError("Cannot call a class as a function")
            }
              , n = function() {
                function t(t, e) {
                    for (var n = 0; n < e.length; n++) {
                        var i = e[n];
                        i.enumerable = i.enumerable || !1,
                        i.configurable = !0,
                        "value"in i && (i.writable = !0),
                        Object.defineProperty(t, i.key, i)
                    }
                }
                return function(e, n, i) {
                    return n && t(e.prototype, n),
                    i && t(e, i),
                    e
                }
            }()
              , i = Object.assign || function(t) {
                for (var e = 1; e < arguments.length; e++) {
                    var n = arguments[e];
                    for (var i in n)
                        Object.prototype.hasOwnProperty.call(n, i) && (t[i] = n[i])
                }
                return t
            }
              , r = function() {
                function t(n) {
                    var i = !(arguments.length > 1 && void 0 !== arguments[1]) || arguments[1]
                      , r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : []
                      , o = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 5e3;
                    e(this, t),
                    this.ctx = n,
                    this.iframes = i,
                    this.exclude = r,
                    this.iframesTimeout = o
                }
                return n(t, [{
                    key: "getContexts",
                    value: function() {
                        var t = [];
                        return (void 0 !== this.ctx && this.ctx ? NodeList.prototype.isPrototypeOf(this.ctx) ? Array.prototype.slice.call(this.ctx) : Array.isArray(this.ctx) ? this.ctx : "string" == typeof this.ctx ? Array.prototype.slice.call(document.querySelectorAll(this.ctx)) : [this.ctx] : []).forEach((function(e) {
                            var n = t.filter((function(t) {
                                return t.contains(e)
                            }
                            )).length > 0;
                            -1 !== t.indexOf(e) || n || t.push(e)
                        }
                        )),
                        t
                    }
                }, {
                    key: "getIframeContents",
                    value: function(t, e) {
                        var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : function() {}
                          , i = void 0;
                        try {
                            var r = t.contentWindow;
                            if (i = r.document,
                            !r || !i)
                                throw new Error("iframe inaccessible")
                        } catch (t) {
                            n()
                        }
                        i && e(i)
                    }
                }, {
                    key: "isIframeBlank",
                    value: function(t) {
                        var e = "about:blank"
                          , n = t.getAttribute("src").trim();
                        return t.contentWindow.location.href === e && n !== e && n
                    }
                }, {
                    key: "observeIframeLoad",
                    value: function(t, e, n) {
                        var i = this
                          , r = !1
                          , o = null
                          , s = function s() {
                            if (!r) {
                                r = !0,
                                clearTimeout(o);
                                try {
                                    i.isIframeBlank(t) || (t.removeEventListener("load", s),
                                    i.getIframeContents(t, e, n))
                                } catch (t) {
                                    n()
                                }
                            }
                        };
                        t.addEventListener("load", s),
                        o = setTimeout(s, this.iframesTimeout)
                    }
                }, {
                    key: "onIframeReady",
                    value: function(t, e, n) {
                        try {
                            "complete" === t.contentWindow.document.readyState ? this.isIframeBlank(t) ? this.observeIframeLoad(t, e, n) : this.getIframeContents(t, e, n) : this.observeIframeLoad(t, e, n)
                        } catch (t) {
                            n()
                        }
                    }
                }, {
                    key: "waitForIframes",
                    value: function(t, e) {
                        var n = this
                          , i = 0;
                        this.forEachIframe(t, (function() {
                            return !0
                        }
                        ), (function(t) {
                            i++,
                            n.waitForIframes(t.querySelector("html"), (function() {
                                --i || e()
                            }
                            ))
                        }
                        ), (function(t) {
                            t || e()
                        }
                        ))
                    }
                }, {
                    key: "forEachIframe",
                    value: function(e, n, i) {
                        var r = this
                          , o = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : function() {}
                          , s = e.querySelectorAll("iframe")
                          , a = s.length
                          , l = 0;
                        s = Array.prototype.slice.call(s);
                        var u = function() {
                            --a <= 0 && o(l)
                        };
                        a || u(),
                        s.forEach((function(e) {
                            t.matches(e, r.exclude) ? u() : r.onIframeReady(e, (function(t) {
                                n(e) && (l++,
                                i(t)),
                                u()
                            }
                            ), u)
                        }
                        ))
                    }
                }, {
                    key: "createIterator",
                    value: function(t, e, n) {
                        return document.createNodeIterator(t, e, n, !1)
                    }
                }, {
                    key: "createInstanceOnIframe",
                    value: function(e) {
                        return new t(e.querySelector("html"),this.iframes)
                    }
                }, {
                    key: "compareNodeIframe",
                    value: function(t, e, n) {
                        if (t.compareDocumentPosition(n) & Node.DOCUMENT_POSITION_PRECEDING) {
                            if (null === e)
                                return !0;
                            if (e.compareDocumentPosition(n) & Node.DOCUMENT_POSITION_FOLLOWING)
                                return !0
                        }
                        return !1
                    }
                }, {
                    key: "getIteratorNode",
                    value: function(t) {
                        var e = t.previousNode();
                        return {
                            prevNode: e,
                            node: (null === e || t.nextNode()) && t.nextNode()
                        }
                    }
                }, {
                    key: "checkIframeFilter",
                    value: function(t, e, n, i) {
                        var r = !1
                          , o = !1;
                        return i.forEach((function(t, e) {
                            t.val === n && (r = e,
                            o = t.handled)
                        }
                        )),
                        this.compareNodeIframe(t, e, n) ? (!1 !== r || o ? !1 === r || o || (i[r].handled = !0) : i.push({
                            val: n,
                            handled: !0
                        }),
                        !0) : (!1 === r && i.push({
                            val: n,
                            handled: !1
                        }),
                        !1)
                    }
                }, {
                    key: "handleOpenIframes",
                    value: function(t, e, n, i) {
                        var r = this;
                        t.forEach((function(t) {
                            t.handled || r.getIframeContents(t.val, (function(t) {
                                r.createInstanceOnIframe(t).forEachNode(e, n, i)
                            }
                            ))
                        }
                        ))
                    }
                }, {
                    key: "iterateThroughNodes",
                    value: function(t, e, n, i, r) {
                        for (var o, s = this, a = this.createIterator(e, t, i), l = [], u = [], c = void 0, h = void 0; o = void 0,
                        o = s.getIteratorNode(a),
                        h = o.prevNode,
                        c = o.node; )
                            this.iframes && this.forEachIframe(e, (function(t) {
                                return s.checkIframeFilter(c, h, t, l)
                            }
                            ), (function(e) {
                                s.createInstanceOnIframe(e).forEachNode(t, (function(t) {
                                    return u.push(t)
                                }
                                ), i)
                            }
                            )),
                            u.push(c);
                        u.forEach((function(t) {
                            n(t)
                        }
                        )),
                        this.iframes && this.handleOpenIframes(l, t, n, i),
                        r()
                    }
                }

 

 

2.通过js自身加密业务代码,然后在执行是进行解密。

将js文件源码作为文本文件加密,再使用或者调用的过程中通过我们写的代码进行解密还原,然后通过类似eval的函数进行运行,这样用户仅仅将加密解密部分代码暴露,其他业务代码全是将源码加密的状态,如果再结合第1中方法,对加解密部分代码处理,将可以有效的阻止用户正常阅读,从而保证其他业务代码的安全行。也就是你需要在读懂我的加解密算法后,再进行代码还原。增加代码的安全行。

加密效果:☆☆☆

维护难度:☆☆☆☆

 

 

 

3.从nodejs源码入手,在不影响运行效率的基础上,对加密代码进行解密后执行。

js的源码由于是解释运行,所以从源码特性层面已经决定了,你的代码不安全,但是js文件能够执行的前提,是需要nodejs的二进制程序进行解释运行。那nodejs.exe这个文件是用什么开发的呢?一番查阅后发现,是C++开发的。那么我们是否可以从nodejs的源码入手对文件进行加密呢?答案是肯定的,我们通过阅读代码去寻找加载js文件的地方,增加解密代码,再通过重新编译即可得到支持自定义加密文件的nodejs。linux或其他版一样。

 

加密效果:☆☆☆☆☆

维护难度:☆

 

 

三、解决方式

写了那么多了,我们做了很多尝试。终于发现突破口,考虑到大家可能不会C++,可直接修改js代码实现代码的解密:

废话不多说:

上修改位置:

node-v10.5.0\lib\internal\modules\cjs\loader.js

// Native extension for .js

Module._extensions['.js'] = function(module, filename) {
//在这里增加解密代码即可实现整个js代码的加密.
....

}

 

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值