I would like to let my users create Ruby scripts that do computation on some data residing on the web server and then outputs results. The scripts are executed on the server. Is there any way to do this securely?
我希望让我的用户创建Ruby脚本,在web服务器上的一些数据上进行计算,然后输出结果。脚本在服务器上执行。有什么办法可以安全地做这件事吗?
More specifically, I would like to:
更具体地说,我想:
- restrict the resources the script can use (memory and cpu), and limit its running time
- 限制脚本可以使用的资源(内存和cpu),并限制其运行时间
- restrict which core classes the script can use (e.g. String, Fixnum, Float, Math etc)
- 限制脚本可以使用的核心类(例如字符串、Fixnum、Float、Math等)
- let the script access and return data
- 让脚本访问和返回数据。
- output any errors to the user
- 向用户输出任何错误
Are there any libraries or projects that do what I'm asking for? If not in Ruby, maybe some other language?
有没有什么图书馆或项目能做我想做的?如果不是Ruby,可能是其他语言?
1 个解决方案
#1
17
You can use a "blank slate" as a clean room, and a sandbox in which to set the safe level to 4.
您可以使用一个“空白石板”作为一个干净的房间,和一个沙箱,在其中设置安全级别为4。
A blank slate an object you've stripped all the methods from:
一个空白的石板,一个对象,你已经从:
class BlankSlate
instance_methods.each do |name|
class_eval do
unless name =~ /^__|^instance_eval$|^binding$|^object_id$/
undef_method name
end
end
end
end
A clean room is an object in which context you evaluate other code:
一个干净的房间是一个对象,你在其中评估其他代码的上下文:
clean_room = BlankSlate.new
Read a command from an untrusted source, then untaint it. Unless untainted, Ruby will refuse to eval the string in a sandbox.
从不受信任的源读取命令,然后删除它。除非没有被污染,否则Ruby将拒绝在沙箱中对字符串求值。
command = gets
command.untaint
Now execute the string in a sandbox, cranking the safe level up as high as it will go. The $SAFE level will go back to normal when the proc ends. We execute the command in the context of the clean room's binding, so that it can only see the methods and variables that the clean room can see (remember, though, that like any object, the clean room can see anything in global scape).
现在在沙箱中执行字符串,将安全级别提升到最高。当proc结束时,$SAFE水平将恢复到正常水平。我们在clean room的绑定上下文中执行该命令,以便它只能看到clean room可以看到的方法和变量(请记住,与任何对象一样,clean room可以看到全局视图中的任何内容)。
result = proc do
$SAFE = 4
clean_room.instance_eval do
binding
end.eval(command)
end.call
print the result:
打印结果:
p result
#1
17
You can use a "blank slate" as a clean room, and a sandbox in which to set the safe level to 4.
您可以使用一个“空白石板”作为一个干净的房间,和一个沙箱,在其中设置安全级别为4。
A blank slate an object you've stripped all the methods from:
一个空白的石板,一个对象,你已经从:
class BlankSlate
instance_methods.each do |name|
class_eval do
unless name =~ /^__|^instance_eval$|^binding$|^object_id$/
undef_method name
end
end
end
end
A clean room is an object in which context you evaluate other code:
一个干净的房间是一个对象,你在其中评估其他代码的上下文:
clean_room = BlankSlate.new
Read a command from an untrusted source, then untaint it. Unless untainted, Ruby will refuse to eval the string in a sandbox.
从不受信任的源读取命令,然后删除它。除非没有被污染,否则Ruby将拒绝在沙箱中对字符串求值。
command = gets
command.untaint
Now execute the string in a sandbox, cranking the safe level up as high as it will go. The $SAFE level will go back to normal when the proc ends. We execute the command in the context of the clean room's binding, so that it can only see the methods and variables that the clean room can see (remember, though, that like any object, the clean room can see anything in global scape).
现在在沙箱中执行字符串,将安全级别提升到最高。当proc结束时,$SAFE水平将恢复到正常水平。我们在clean room的绑定上下文中执行该命令,以便它只能看到clean room可以看到的方法和变量(请记住,与任何对象一样,clean room可以看到全局视图中的任何内容)。
result = proc do
$SAFE = 4
clean_room.instance_eval do
binding
end.eval(command)
end.call
print the result:
打印结果:
p result