背景
前一阵子比特股的创始人Daniel Larimer质疑了lisk体系中的一系列题目,绝大多数都被lisk的创始人之一Max正面回应过了,详细能够看看这个http://ethereum.stackexchange…
然则有一个题目Max没有回应或许说还没有提出处理计划。
那就是lisk侧链的运转环境,Larimer说
“Lisk所面对的大多数题目,都能够经由过程一个高度定制的JavaScript 环境来处理。”
不然,lisk的体系面对两大磨练:
起首,也是最主要的,lisk现在的沙箱机制不足以限定侧链代码的权限,也就是说没法运转不受信托的代码,那些代码可能会偷取效劳器的症结信息,或许直接对效劳器举行损坏
其次,是关于侧链开辟者的,lisk的侧链代码是运转在一个具有悉数才能的javascript环境,这里面有些能够致使不确定要素的函数,比方Math.random,lisk官方的开辟文档迥殊指出愿望开辟者避开这些函数,这对开辟者会形成心智累坠,如果是一个定制版的javascript环境呢,直接把那些致使不确定要素的函数干掉,开辟者基础不须要花费分外的精神去避开那些圈套。
lisk的沙箱平安题目
我们先说说为何要用沙箱。沙箱(sandbox)是云盘算平台普遍采纳的平安防范措施,是一种接见掌握机制,其目标是为了限定运用代码的权限,防备运用代码对体系举行随便的接见和损坏,由于在云盘算平台中,运用代码是由林林总总的第三方开辟者完成的,他们的代码是不能被信托的,须要沙箱来做一层断绝,让这些运用代码只能做有限的事变。
lisk在区块链范畴是很类似于云盘算平台的,他们供应一些效劳,许可第三方开辟者基于这些效劳构建他们本身的运用顺序(即dapps)。
所以lisk也须要沙箱机制来保证dapps的作者没法作歹,lisk的做法是供应一个定制版的nodejs环境来到达这一目标。
详细完成在这段代码里,https://github.com/LiskHQ/lis…
我经由剖析,发明这个sandbox有名无实,只是运用管道手腕完成了历程间通信,而且是运用一种绕弯的体式格局完成的。nodejs的历程间通信能够经由过程javascript代码直接完成,为何要用c++来完成呢?
我带着这个疑问,和一些希冀,亲手做了一个试验。
我起首运用lisk-cli建立一个hello world侧链
lisk-cli dapp -a
接着我在侧链顺序的入口处 加了一段代码
console.log(require("fs").readFileSync("../../config.json"))
然后运转之,因而我得到了这个效劳器主节点的受托人的一切暗码
"forging": {
"secret": [
"wKyoJM1vS4ucHmWvxDSdcpC23mJwqfg3G6MKZoXaFfcnWHTqo7",
"2aTWYPpQidVunxTg3y8YESYps7za6f9d4wYn9Gy2GuGnE7JX7V",
"65uZNjL36Bdg2tkJnueYkd2n6YPe76fpdeYtgu7fso1m385mwD",
…………
果真,这个沙箱并没有起断绝的作用,具有治理员的权限,这即是给黑客敞开了大门。
有人说,lisk体系设置了二级暗码,你获取了他的一级暗码,照样没法偷取他们的钱。
也有人说,能够经由过程Linux本身的权限机制,给侧链代码一个初级用户,使之没法接见其他用户的文件。
这些都是治标不治本的要领,基础处理门路是根据lisk预先想象的那样,要让沙箱名不虚传,做到真正的环境断绝,要让侧链代码对外界一窍不通。
处理计划
那末,怎样完成真正的沙箱呢?有许多种计划,比方跳过nodejs,直接运用v8引擎,或许运用历程级别的权限掌握,比方windows体系的SetWindowsHookEx,固然,lisk现在并不盘算支撑windows版本的完全版钱包,那末在linux体系中能够运用seccomp手艺。
我这里有种更简朴的要领,那就是应用nodejs自带的vm模块。
第一步 建立原生的javascript虚拟机
var vm = require('vm');
var context = vm.createContext();
vm.runInContext(sideChainCode, context);
这几行代码完成了对侧链代码的断绝,sideChainCode中只能举行地道的运算逻辑,只能运用少许的v8引擎内置的javascript规范库。以至连setTimeout,console.log都没有。
我们须要做些分外的事情。
比方,给运转环境增加setTimeout和clearTimeout
context.setTimeout= function(fn, delay) {
if (typeof(fn) == 'string') {
setTimeout(new Function(fn), delay)
} else {
setTimeout(fn, delay)
}
};
context.clearTimeout = clearTimeout;
增加日记打印功用,让侧链的日记,转发到主体系的中
global.print = send.bind(global, 'stdout');
global.console = { log: send.bind(global, 'stdout') };
global.process = {
stdout: { write: send.bind(global, 'stdout') }
};
global.postMessage = send.bind(global, 'message');
别的,还能够禁用那些致使不确定要素的函数
global.Math.random = undefined;
这些都做完今后,侧链代码的接见权限就被限定在一个狭窄的范围内了。它们没法运用require,fs,http等nodejs内置的规范库。
如许平安的目标到达了,然则激发另一个题目,那就是功用性的题目了,不能运用那些分外的库,只要js的规范库也太不方便了,许多庞杂功用没法完成,迥殊是没有了require以后,连模块化都做不到了。
所以我们须要第二步。
第二步 webpack
webpack本来是一个前端经常使用的打包计划,用于模块化的治理前端项目。许多人疏忽了其实在后端webpack一样实用,而且能够把node_modules里的库,以至nodejs的一部份内置库一同打包。
也就是说前端能用的js库,除了UI相干的以外,在侧链沙箱内,也都能够用,比方async,bytebuffer,crypto,js-nacl,bignum等等,这关于侧链来讲够用了。
那些不能用的库,比方文件体系、多历程、收集模块,恰是我们想要扬弃的。
vm + webpack的组合可谓圆满。
这是一日千里的前端手艺带给javascript这门言语的福利,也是以太坊的solidity等新言语瞠乎其后的。
不过我们还须要一些扫尾的事情
第三步 扫清停滞
现在侧链代码中有些处所运用了一些比较庞杂的库,比方ed2curve,涉及到异常多的依靠,我们认为是没有必要的,这部份功用能够在主链中供应,经由过程历程间通信以api的体式格局供应给侧链运用。
如许也能够减轻侧链代码的累坠,还能够让侧链开辟者越发轻松。这些代码对全部框架的影响异常小,能够疏忽不计,然则它们依靠的库却占用了一半以上的代码量,个中还包含了沙箱环境不许可的一些操纵。
经由剖析,我发明只须要禁用modules/api/crypto.js中的两个函数即可
Crypto.prototype.encrypt
Crypto.prototype.decrypt
别的,js-nacl这个库里依靠了fs模块,然则相干函数并没有被用到,临时经由过程手工修正的体式格局,把fs相干代码去掉就能够一般打包并运转了。
末了,我把一个完全的侧链项目和主链框架中的症结代码打包放在这里了。http://o7dyh3w0x.bkt.clouddn….
关于侧链和区块链开辟的题目,迎接加群:485979564,一同议论交换