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

被折叠的 条评论
为什么被折叠?



