本质上,我想创建一个程序,该程序将运行一些定义某些方法或类的不受信任的代码,然后针对它运行不受信任的 rspec 规范。
我对沙盒 Ruby 进行了一些研究,来自 rubyconf 的这段视频特别有用。在查看了几个解决方案之后,似乎最有帮助的两个是rubycop,它基本上对代码进行静态分析,以及jruby 沙箱(都在上面的视频中介绍)。我的直觉告诉我,jruby 沙盒可能更安全,但我很可能是错的。
这是我想做的一个完全不安全的例子:
code = <<-RUBY
class Person
def hey
"hey!"
end
end
RUBY
spec = <<-RUBY
describe Person do
let(:person) { Person.new }
it "says hey" do
person.hey.should == "hey!"
end
end
RUBY
# code and spec will be from user input (unsafe)
eval code
require 'rspec/autorun'
eval spec
这一切都很好,但代码显然需要被沙盒化。system("rm -rf /*")
一些天才提交,fork while fork
或者同样危险的东西,这将是几分钟的事情。
我用jruby沙箱做了各种尝试......
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.activate! # lock it down
sand.eval code
puts sand.eval spec
该代码引发此异常:
Sandbox::SandboxException: NoMethodError: undefined method `require' for #<RSpec::Core::Configuration:0x7c3cfaab>
这是因为 RSpec 在沙箱被锁定后试图要求一些东西。
因此,我试图通过调用 empty 来强制 RSpec 在沙箱被锁定之前需要一些东西describe
:
sand = Sandbox::Safe.new
sand.eval("require 'rspec/autorun'")
sand.eval("describe("") { }")
sand.activate! # lock it down
sand.eval code
sand.eval spec
我明白了:
Sandbox::SandboxException: NameError: uninitialized constant RSpec
这基本上意味着RSpec
沙盒中不存在。这很奇怪,考虑到sand.eval("require 'rspec/autorun'")
返回 true,并且前面的示例确实有效(RSpec 的自动加载器开始运行)。
不过,这可能是 gems 和这个特定沙箱的问题。沙盒对象实际上支持一个方法#require
,它本质上是绑定到的Kernel.require
,因此不能加载 gems。
它开始看起来像使用这个沙箱可能真的无法使用 rspec。主要问题是试图将其实际加载到沙箱中。我什至尝试过这样的事情:
require 'rspec'
sand.ref(RSpec) # open access to local rspec
但它没有任何东西。
所以,我的问题有两个:
- 有没有人有任何关于如何让它与 jruby 沙箱一起工作的好主意?
- 如果不是,rubycop的安全性如何?显然codeschool使用它,所以它必须经过很好的测试......能够使用 ruby 1.9 而不是 jruby 会很好。