Подтвердить что ты не робот

Как создать безопасную песочницу Lua?

Итак, Lua кажется идеальным для реализации безопасных "пользовательских скриптов" внутри моего приложения.

Однако большинство примеров внедрения lua, похоже, включают загрузку всех стандартных библиотек, включая "io" и "package".

Поэтому я могу исключить эти библиотеки из моего интерпретатора, но даже базовая библиотека включает в себя функции "dofile" и "loadfile", которые обращаются к файловой системе.

Как я могу удалить/заблокировать любые небезопасные функции, подобные этим, не вдаваясь с интерпретатором, который даже не имеет базового элемента, такого как функция "ipairs"?

4b9b3361

Ответ 1

Вы можете установить функциональную среду, в которой вы запускаете ненадежный код, через setfenv(). Здесь схема:

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

Функция user_script может получить доступ только к тому, что находится в ее среде. Таким образом, вы можете в явном виде добавить функции, к которым должен иметь доступ ненадежный код (белый список). В этом случае пользователь script имеет доступ только к ipairs, но ничего больше (dofile, loadfile и т.д.).

См. Lua Sandboxes для примера и дополнительную информацию о песочнице lua.

Ответ 2

Вот решение для Lua 5.2 (включая среду примера, которая также будет работать в 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)

Ответ 4

Один из самых простых способов устранения нежелательных проблем - сначала загрузить Lua script вашего собственного проекта, который выполняет следующие действия:

load = nil
loadfile = nil
dofile = nil

В качестве альтернативы вы можете использовать setfenv для создания ограниченной среды, в которую вы можете вставить определенные безопасные функции.

Полностью безопасная песочница немного сложнее. Если вы загружаете код из любого места, имейте в виду, что прекомпилированный код может привести к сбою Lua. Даже полностью ограниченный код может переходить в бесконечный цикл и блокировать бесконечно, если у вас нет системы для его закрытия.

Ответ 5

Вы можете использовать функцию lua_setglobal, предоставляемую API Lua, чтобы установить эти значения в глобальном пространстве имен на nil, что эффективно предотвратит доступ к ним любых пользовательских скриптов.

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

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

...etc...

Ответ 6

Если вы используете 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

Ответ 7

Вы можете переопределить (отключить) любую функцию Lua, которую вы хотите, а также использовать metatables для большего контроля.