加载中…
个人资料
新浪研发中心
新浪研发中心
  • 博客等级:
  • 博客积分:0
  • 博客访问:404,533
  • 关注人气:289
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

Nodejs

(2011-11-23 10:50:07)
标签:

nodejs

杂谈

作者:张任重

这几周我在负责nodejsSAE平台化问题,主要任务是制作nodejs的沙盒,保证nodejsSAE上稳定安全的运行。

首先简单介绍一下nodejsnodejs是资深C语言程序员Ryan Dahl 依据googlejavescript引擎V8开发的web I/O服务器,它采用了基于事件驱动的模式,绕开了server端线程阻塞的弊端,在高并发的情景下,性能优秀。

移植nodejs,我们要考虑的主要有以下几个问题:

1、 对于影响安全和性能的函数和模块实现禁用。

2、 实现用户间的文件隔离,同时禁止本地写

3、 对于用户使用http抓取的数据进行监控和统计

4、 内存限制

5、 代码容量限制

6、 Cpu使用的限制

这次我主要介绍下SAE中对于模块禁用、文件隔离、和http模块部分的修改。

一、模块禁用

Nodejs的模块分为两部分,一部分是用C实现的模块,比如:bufferstdio等,另一部分是用js实现的模块比如netdns等。对于C的模块,nodejs通过node.h提供的NODE_MODULE方法将模块存储在变量_module里。在src/node_extensions.cc中提供了get_builtin_module(name)接口获取这些模块;而对于js的模块,nodejssrc/node.js中实现了一个NativeModule对象用于管理js模块,它通过调用process.binding(“natives”)把所有内置的js模块放在NativeModule._source上,并提供require接口供调用。

为了提高模块加载的效率,nodejsbinding函数和require函数中都增加了缓存机制,在首次加载模块的时候,模块会copy的缓存中,以后的模块加载实际上只是从缓存中获得模块的接口,这样的机制使得nodejs在模块加载方面十分高效。

Nodejs模块的调用形式如下:

加载C++模块(stdio为例)

process.binding("stdio")->get_builtin_module("stdio")-> _module -> NODE_MODULE(node_stdio, node::Stdio::Initialize)(定义)

加载js模块(net为例)

require("net") -> NativeModule.require("net") -> process.binding("natives")["net"] -> DefineJavaScript() -> natives[] -> node_natives.h

为了在require中实现对函数和模块的禁用,首先我为nodejs增加了一个全局变量用来区分nodejs自身的require调用和用户的require调用,这样在用户使用require加载模块的时候,如果检测到模块中游需要禁用的函数,则将该函数接口封掉,不提供给用户。如果检测到模块应该禁用,则直接抛出异常,告知用户SAE不支持此模块。这样的修改禁止了用户对js模块的使用,但是有一个漏洞,就是用户可以利用binding接口直接调用C模块,自己实现一份禁用的函数,为了解决这个问题,我们对用户禁用了binding函数,阻止用户调用C语言编写的nodejs模块,这样我们就比较好的解决了函数和模块禁用的问题。

1SAE禁止用户加载child_process模块,用户如果试图require('child_process'),则会得到如下报错。

      Nodejs


2:如果用户试图process.binding('child_process'),则会得到如下报错:

      
Nodejs


二、文件隔离

文件隔离包括两部分,一方面要求用户之间进行隔离,一方面要限制用户的本地写操作,这主要是因为在SAE的分布式环境中,用户代码保存在不同的机器上,允许用户本地写操作,会导致用户各地代码不一致,作为替代,SAE为用户提供了多种形式可替代本地读写,比如tmpfsmcstorage

对于用户之间的隔离,可以通过linux的系统权限,将用户目录隔离;如果希望通过nodejs本身的代码修改,则可以对用户本地I/O操作的文件名进行判断,对于读权限,用户只拥有自己目录和SAE规定目录(tmpfsmcstorage)下的读权限。对于写权限,用户只可以写到SAE规定的目录下。

3:如果用户写到SAE规定以外的目录时,得到如下报错:

   Nodejs

三、http模块的修改

SAE中,用户的数据抓取都是通过fetchurl服务来进行的,fetchurl服务实际上起到了中间层的作用。如果希望用户通过fetchurl接口获取数据,则必须使用accesskeysecretkey来标记自己的身份,因此我们需要修改nodejs,使其可以获取到SAE环境中的accesskeysecretkey,这实际上是通过用户请求的http header来获取的,当用户的server接收web端的http请求时,httpheader中包含了accesskeysecretkey。在用户通过http模块进行数据获取时,最终会调用ClientRequest,我主要修改了这部分的逻辑,首先,逻辑中一定会将agent设置为fetchurl服务的url,同时根据accesskeysecretkey组装fetchurl服务所需的http header,用户实际请求的url是保存在header['FetchUrl']中的。经过这样的修改后,用户的数据获取请求会发给fetchurlfetchuurl会根据header完成用户的数据获取请求,然后传回给用户,这样我们就达到了我们的目的。

以上就是SAEnodejs的初期改造,目前我们还在进一步实现nodejs的沙盒,以保证nodejs尽快在SAE上运行。

 

 

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有