Ruby 如何获取传递给eval方法的块的返回值?
我想实现一些类似沙箱的东西,它可以Ruby 如何获取传递给eval方法的块的返回值?,ruby,eval,return-value,yield,Ruby,Eval,Return Value,Yield,我想实现一些类似沙箱的东西,它可以 求值给定字符串 在与eval相同的上下文中执行给定的块 返回块的结果 沙盒的目的是检查易受攻击代码的内容——函数、变量、e.t.c 这是我的说明书 it 'returns return value of given block' do value = Sandbox.secure_eval('hoge = ["hoge", "fuga"]') do hoge[0] end expect(value).to eq('hoge') end
- 求值给定字符串
- 在与eval相同的上下文中执行给定的块
- 返回块的结果
it 'returns return value of given block' do
value = Sandbox.secure_eval('hoge = ["hoge", "fuga"]') do
hoge[0]
end
expect(value).to eq('hoge')
end
这是我的沙盒实现
require 'timeout'
module Sandbox
def self.secure_eval(code, timeout: 5, safe_level: 2)
raise ArgumentError, 'please set call back by block' unless block_given?
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
eval code do
yield
end
end
end
proc.call
end
end
但是#secure_eval返回eval的结果,在本例中为[“hoge”,“fuga”],无法捕获块的返回值
require 'timeout'
module Sandbox
refine Binding do
def method_missing(meth, *args, &block)
self.eval(meth.to_s)
end
end
def self.secure_eval(code, timeout: 5, safe_level: 2, &block)
raise ArgumentError, 'please set call back by block' unless block_given?
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
binding = binding()
binding.eval(code)
binding.instance_eval(&block)
end
end
proc.call
end
end
using Sandbox # Activate the refinement so we can use x, y, z directly
Sandbox.secure_eval('x = [1,2,3]; y = 0; z = { key: "Hello!" }') do
x[1] # => 2
y # => 0
z[:key] # => "Hello!"
end
我该怎么做?您可以使用
yield
将评估结果返回到块中。您只需产生值;因此,我将您的yield
更改为yield eval code
。在你给沙盒的块中,你必须将这个结果绑定到一个块变量。secure\u eval
的结果将是块的结果,如您所愿
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
yield eval code # <= This line changed
end
end
Sandbox.secure_eval('hoge = ["hoge", "fuga"]') { |hoge| hoge[0] }
# => "hoge"
Sandbox.secure_eval('2 ** 4') { |result| result - 5 }
# => 11
您可以使用yield
将eval结果返回到块。您只需产生值;因此,我将您的yield
更改为yield eval code
。在你给沙盒的块中,你必须将这个结果绑定到一个块变量。secure\u eval
的结果将是块的结果,如您所愿
proc = Proc.new do
Timeout::timeout timeout do
$SAFE = safe_level
yield eval code # <= This line changed
end
end
Sandbox.secure_eval('hoge = ["hoge", "fuga"]') { |hoge| hoge[0] }
# => "hoge"
Sandbox.secure_eval('2 ** 4') { |result| result - 5 }
# => 11
我不认为块在任何地方都可以调用-eval
不接受块…引述如下:“然而,$SAFE
并没有为执行不受信任的代码提供一个安全的环境。”您永远不应该依赖Ruby内置的$SAFE
或任何其他通用的“安全代码执行”机制(或大多数其他语言)在执行不受信任(以及潜在的恶意)代码时保护您免受伤害。你的沙箱根本不是沙箱!我不认为块在任何地方都可以调用-eval
不接受块…引述如下:“然而,$SAFE
并没有为执行不受信任的代码提供一个安全的环境。”您永远不应该依赖Ruby内置的$SAFE
或任何其他通用的“安全代码执行”机制(或大多数其他语言)在执行不受信任(以及潜在的恶意)代码时保护您免受伤害。你的沙箱根本不是沙箱!谢谢你的回复。您的代码似乎正常工作,但我希望我的沙盒可以像下面那样工作:sandbox.secure_eval('hoge=[“hoge”,“fuga”];piyo=“piyo”'){hoge[0]}#=>“hoge”有什么办法吗?@Mekajiki Ah所以您希望能够访问您在eval
中声明的任何变量。。我不知道这是否可行,eval
只返回最后一个表达式的值,而不返回中间表达式的值。也许这是可能的,但我不知道一种方法。@Mekajiki我已经用一种方法更新了我的帖子,可以访问其他定义的变量。你必须在绑定中添加*args
和block
到eval
,但是对block这样做一点都不简单。@hakcho我添加了改进的用法,现在需要使用沙盒来启用补丁绑定行为,而不是全局启用。感谢您的回复。您的代码似乎正常工作,但我希望我的沙盒可以像下面那样工作:sandbox.secure_eval('hoge=[“hoge”,“fuga”];piyo=“piyo”'){hoge[0]}#=>“hoge”有什么办法吗?@Mekajiki Ah所以您希望能够访问您在eval
中声明的任何变量。。我不知道这是否可行,eval
只返回最后一个表达式的值,而不返回中间表达式的值。也许这是可能的,但我不知道一种方法。@Mekajiki我已经用一种方法更新了我的帖子,可以访问其他定义的变量。你必须在绑定中添加*args
和block
到eval
,但是对block这样做一点都不简单。@hakcho我添加了改进的用法,现在需要使用Sandbox
来启用补丁绑定行为,而不是全局启用。