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. , 这个很不人性化,需要考虑其他的解决方案

你可能感兴趣的:(Ruby)