Ruby Sandbox 实现运行客户代码

碰到的问题是需要 运行客户自己编程的代码,同时要保证安全性,在碰到 system("rm")时,保证不抓狂

 

Ruby 自身是带有安全机制的,详细参看 Programming Ruby 2nd , 第25章 Ruby 安全

简略的说Ruby有四个安全级(详细参看Programming Ruby),等级4正是客户代码运行的理想的环境,不会污染到其他代码,也不会破坏系统,相当严格

 

示例代码如下:

 

def safely(code)
	sandbox = lambda do
		input = "something"
		$SAFE = 4
		eval code
	end
	sandbox.call
end

code = File.new("file.rb").read
result = safely(code)
puts result

 

 

代码很简单

 

file.rb读入的code 是 "input * 2"
sandbox提供了code的运行环境 : input作为输入变量 , 提升了$SAFE等级
得到的输出是 "somethingsomething"
当我们在code中加入 system("rm") / system("del *") 时,得到以下错误
try.rb:5:in `safely': (eval):1:in `system': Insecure operation - system (Securit
yError)
Insecure operation - system (SecurityError)
$SAFE 成功保护了我们的系统 , 当试图侵入源程序,也会得到错误
问题讨论:
1. $SAFE = 4 ,是个十分严格的规定,之后的代码不能侵入系统、不能修改"未污染"的对象等等,当安全级提升到4时,之后我们的程序代码怎么能正常运行而不受影响?$SAFE 的作用域 被绑定在了一个Proc内,仅在sandbox中有效,不对外面的代码产生安全级的影响。详细参看 : $SAFE is Proc-local(http://www.davidflanagan.com/2008/11/safe-is-proc-lo.html)
2. 考虑以下代码
def safely(code)
	temp_box = lambda do
		input = "something"
		eval code
	end
	sandbox = lambda do		
		$SAFE = 4
		temp_box.call
	end
	sandbox.call
end

code = File.new("file.rb").read
result = safely(code)
puts result
当code中的代码是 system("shutdown")的时候,你很有可能看不到下面的内容(是很有可能,可以来测试你是不是有管理员的权限,当然也可以用 system("format")测试,未知结果)
temp_box 的运行环境 $SAFE 是默认值0,不受之前$SAFE的影响,一定要注意
3. 剩下待解决的问题就是:code中不能声明函数,Programming Ruby 2nd中这样描述:不能在未污染的类或模块内定义、重定义、删除或取消定义方法。需要寻找方法让code中能声明函数.
补充:关于问题3的讨论
1. 考虑以下代码
class Test
	def safely
		sandbox = lambda do
			self.class.taint
			$SAFE = 4
			#code 
			def something
				"success !!"
			end
			something
			#code end
		end
		sandbox.call
	end
end

result = Test.new.safely
puts result
我们将在code域内成功定义方法,并得到输出 "success!!"
但是注意到 self.class.taint , 我们就看到整个Test类被污染了,something方法会渗透添加到 所有Test对象中,这违背了我们期望的沙盒原则
需要注意的是: def 中的def 是在类中添加实例方法
2. 对于以上问题的解决:
class Test
	def safely
		sandbox = lambda do
			self.taint
			$SAFE = 4
			#code 
			def self.something
				"success !!"
			end
			something
			#code end
		end
		sandbox.call
	end
end

result = Test.new.safely
puts result
以上代码只将 self这一个实例 "污染" ,定义了单例方法 something,得到了成功的结果
作为代价,方法定义的时候必须要 self. , 这个很不人性化,需要考虑其他的解决方案
posted @ 2010-03-24 21:24  Tachikoma  阅读(557)  评论(0编辑  收藏  举报