【发布时间】:2019-06-09 11:32:41
【问题描述】:
在我开始之前,让我澄清一下,我已经查看了有关沙盒的现有问题,但我发现的解决方案似乎都没有真正适合我。
我试图实现的不一定是一个完全安全的沙箱来运行不安全的代码,而是提供一个模拟游戏功能的环境(确切地说是战争中的星球大战帝国)我正在修改可以扩展使用 Lua 脚本。游戏提供了一堆我想在这个环境中实现的全局函数,以便能够在不启动游戏本身的情况下测试我的游戏扩展,因为它的调试能力很差。游戏也有一些怪癖。这种情况下的相关问题是使用 upvalues 会产生损坏的保存游戏,所以这就是为什么我们的 Lua 模块必须是全局的。由于我的游戏脚本不包含在单个文件中并且可能需要其他文件,因此使用 setfenv() 调用和声明它们自己的函数来设置环境对我来说并不真正有效,因为这仅适用于您指定的函数,而不适用于它可能调用的任何其他函数。
现在是我的代码本身。到目前为止,我已经尝试通过简单地深度克隆 _G 并在之后将其恢复到以前的状态来实现一个简单的沙箱(这仍然是 WIP,我意识到您仍然可以进行表和环境修改或可能突破沙箱此方法未涵盖的内容;正如我所说,这不是为了运行不安全的代码)。
这是在 sandbox.lua 中:
local function run(func)
-- tested deep_clone with luassert's assert.are_same(), so this should be fine
local g_clone = deep_clone(_G)
-- coroutine is needed because one of the game functions needs
-- to be able to interrupt the script
coroutine.wrap(function()
func()
end)()
for k, v in pairs(_G) do
if not g_clone[k] then
_G[k] = nil
else
_G[k] = g_clone[k]
end
end
end
这是我的测试脚本:
sandbox.run(function()
require "src/declare_global" -- this declares A_GLOBAL = "TEST"
print(A_GLOBAL) -- prints "TEST", everything is fine
end)
print(A_GLOBAL) -- prints nil, as intended
-- as I've restored _G to its former state I should be able to require
-- the script again!
require "src/declare_global"
print("package.loaded: "..tostring(package.loaded["src/declare_global"])) -- prints nil
print(A_GLOBAL) -- prints nil
正如您所看到的,我的问题是,在我在沙箱中完成后,需要仅声明全局的相同文件不再起作用。所以恢复_G的状态可能存在问题,但我不知道它可能是什么。不过,require 调用本身似乎有效。如果我需要的脚本返回一个函数,我仍然可以将它存储在一个变量中并执行它。
非常感谢有关如何解决此问题的任何建议。
【问题讨论】:
-
如果这个沙箱不存在来运行不安全的代码......它的目标到底是什么?你需要什么来阻止函数执行?
-
你是“深度克隆”
_G。之后,您将从其副本“浅恢复”_G。之后,在您的全局环境表中,字段_G不等于表本身。这不好。 -
@NicolBolas - 您的问题的答案在 OP 的问题中。
-
@EgorSkriptunoff:我读了这个问题。它没有解释沙盒的目的是什么。它解释了沙盒应该是什么样子以及脚本不能使用本地变量,但没有说明沙盒应该阻止哪些操作。
-
@NicolBolas - 最好将“沙盒”一词替换为“能够在测试后恢复全局变量的测试/调试环境”。
标签: lua