我如何创建一个安全的 Lua 沙盒?

因此,Lua似乎非常适合在我的应用程序中实现安全“用户脚本”。

但是,大多数嵌入Lua的示例似乎包括加载所有标准库,包括“io”和“package”。

因此,我可以从我的解释器中排除这些库,但是即使基本库也包括访问文件系统的函数“dofile”和“loadfile”。

如何移除/阻止任何这样的不安全函数,而不仅仅是结束具有基本函数(例如“ipairs”函数)的解释器?

原文链接 https://stackoverflow.com/questions/1224708

点赞
stackoverflow用户148870
stackoverflow用户148870

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

lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "io");

lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "loadfile");

...等等...
2009-08-03 21:33:39
stackoverflow用户108130
stackoverflow用户108130

你可以覆盖(禁用)任何想要的 Lua 函数,同时你也可以使用 元表 来获得更多的 _控制_。

2009-08-03 21:34:31
stackoverflow用户147842
stackoverflow用户147842

你可以通过 setfenv() 设置运行不受信任代码的函数环境。以下为概述:

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

user_script 函数只能访问其本地环境。因此,您可以显式添加您想让不受信任代码访问的函数(白名单)。在这种情况下,用户脚本只能访问 ipairs 而不能访问其他函数(如 dofileloadfile 等)。

有关 Lua 沙盒的示例和更多信息,请参见 Lua Sandboxes

2009-08-03 21:37:00
stackoverflow用户5696
stackoverflow用户5696

为了清除不需要的内容,其中最简单的方法之一是首先加载自己定义的Lua脚本,该脚本执行以下操作:

load = nil
loadfile = nil
dofile = nil

或者,可以使用setfenv创建一个受限制的环境,并将特定的安全函数插入其中。

完全安全的沙盒环境稍微有点难度。如果从任何地方加载代码,请注意预编译代码可能会使Lua崩溃。即使是完全受限制的代码,如果没有关闭其系统,也可能进入无限循环并无限期阻塞。

2009-08-04 00:22:17
stackoverflow用户107090
stackoverflow用户107090

Lua live demo 包含一个(专用的)沙箱。 源代码 可以自由获取。

2009-08-04 01:31:09
stackoverflow用户596285
stackoverflow用户596285

以下是适用于 Lua 5.2 的解决方案(包括在 5.1 中也可用的示例环境):

-- 保存指针以指向在沙盒中无法访问的全局变量
local e=_ENV

-- 示例沙盒环境
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)
2011-08-08 12:25:49
stackoverflow用户2853129
stackoverflow用户2853129

如果使用 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("错误:".. msg)
else
    setfenv(f, env)
    local a, b = pcall(f)
    if not a then print("错误:" .. b) end
end
2013-10-07 03:09:59