我如何创build一个安全的Lua沙箱?

所以Lua似乎是在我的应用程序中实现安全的“用户脚本”的理想select。

然而,embeddedlua的大多数例子似乎包括加载所有的标准库,包括“io”和“包”。

所以我可以从我的解释器中排除这些库,但是甚至基本库都包含访问文件系统的函数“dofile”和“loadfile”。

我怎样才能删除/阻止这样的不安全的function,而不是结束了甚至没有像“ipairs”function的基本东西的解释器?

您可以通过setfenv ()设置运行不受信任代码的function环境。 这是一个大纲:

local env = {ipairs} setfenv(user_script, env) pcall(user_script) 

user_script函数只能访问其环境中的内容。 因此,您可以明确地添加您希望不受信任的代码有权访问的function(白名单)。 在这种情况下,用户脚本只能访问ipairs但没有其他的东西( loadfileloadfile等)。

请参阅Lua沙盒以获取有关lua沙盒的更多信息。

下面是Lua 5.2的一个解决scheme(包括一个可以在5.1中工作的示例环境):

 -- save a pointer to globals that would be unreachable in sandbox local e=_ENV -- sample sandbox environment sandbox_env = { ipairs = ipairs, next = next, pairs = pairs, pcall = pcall, tonumber = tonumber, tostring = tostring, type = type, unpack = unpack, coroutine = { create = coroutine.create, resume = coroutine.resume, running = coroutine.running, status = coroutine.status, wrap = coroutine.wrap }, string = { byte = string.byte, char = string.char, find = string.find, format = string.format, gmatch = string.gmatch, gsub = string.gsub, len = string.len, lower = string.lower, match = string.match, rep = string.rep, reverse = string.reverse, sub = string.sub, upper = string.upper }, table = { insert = table.insert, maxn = table.maxn, remove = table.remove, sort = table.sort }, math = { abs = math.abs, acos = math.acos, asin = math.asin, atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos, cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor, fmod = math.fmod, frexp = math.frexp, huge = math.huge, ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max, min = math.min, modf = math.modf, pi = math.pi, pow = math.pow, rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh, sqrt = math.sqrt, tan = math.tan, tanh = math.tanh }, os = { clock = os.clock, difftime = os.difftime, time = os.time }, } function run_sandbox(sb_env, sb_func, ...) local sb_orig_env=_ENV if (not sb_func) then return nil end _ENV=sb_env local sb_ret={e.pcall(sb_func, ...)} _ENV=sb_orig_env return e.table.unpack(sb_ret) end 

然后使用它,你可以调用你的函数( my_func ),如下所示:

 pcall_rc, result_or_err_msg = run_sandbox(sandbox_env, my_func, arg1, arg2) 

Lua现场演示包含一个(专用)沙箱。 来源是免费的。

清除不受欢迎的事件最简单的方法之一是首先加载一个你自己devise的Lua脚本,

 load = nil loadfile = nil dofile = nil 

或者,您可以使用setfenv创build一个可以插入特定安全函数的受限制环境。

完全安全的沙箱有点难度。 如果您从任何地方加载代码,请注意预编译的代码可能会使Lua崩溃。 即使完全受限制的代码也可能进入无限循环,如果没有系统closures,则无限期地阻塞。

您可以使用Lua API提供的lua_setglobal函数将全局名称空间中的这些值设置nil ,这将有效地防止任何用户脚本能够访问它们。

 lua_pushnil(state_pointer); lua_setglobal(state_pointer, "io"); lua_pushnil(state_pointer); lua_setglobal(state_pointer, "loadfile"); ...etc... 

如果你使用的是Lua 5.1,试试这个:

 blockedThings = {'os', 'debug', 'loadstring', 'loadfile', 'setfenv', 'getfenv'} scriptName = "user_script.lua" function InList(list, val) for i=1, #list do if list[i] == val then return true end end local f, msg = loadfile(scriptName) local env = {} local envMT = {} local blockedStorageOverride = {} envMT.__index = function(tab, key) if InList(blockedThings, key) then return blockedStorageOverride[key] end return rawget(tab, key) or getfenv(0)[key] end envMT.__newindex = function(tab, key, val) if InList(blockedThings, key) then blockedStorageOverride[key] = val else rawset(tab, key, val) end end if not f then print("ERROR: " .. msg) else setfenv(f, env) local a, b = pcall(f) if not a then print("ERROR: " .. b) end end 

你可以覆盖(禁用)任何你想要的Lua函数,也可以使用metatables进行更多的控制