programa - lua software
¿Cómo puedo crear un entorno seguro Lua? (7)
Aquí hay una solución para Lua 5.2 (que incluye un entorno de muestra que también funcionaría en 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
Luego, para usarlo, llamarás a tu función ( my_func
) de la siguiente manera:
pcall_rc, result_or_err_msg = run_sandbox(sandbox_env, my_func, arg1, arg2)
Entonces Lua parece ideal para implementar "secuencias de comandos de usuario" seguras dentro de mi aplicación.
Sin embargo, la mayoría de los ejemplos de incrustación de lua parecen incluir la carga de todas las bibliotecas estándar, incluidos "io" y "paquete".
Así que puedo excluir esas librerías de mi intérprete, pero incluso la biblioteca base incluye las funciones "dofile" y "loadfile" que acceden al sistema de archivos.
¿Cómo puedo eliminar / bloquear cualquier función insegura como esta, sin terminar con un intérprete que ni siquiera tiene elementos básicos como la función "ipairs"?
La demostración en vivo de Lua contiene una zona de pruebas (especializada). La source está disponible gratuitamente.
Puede anular (desactivar) cualquier función Lua que desee y también puede usar metatables para tener más control .
Puede establecer el entorno de función en el que ejecuta el código que no es de confianza a través de setfenv (). Aquí hay un resumen:
local env = {ipairs}
setfenv(user_script, env)
pcall(user_script)
La función user_script
solo puede acceder a lo que está en su entorno. Entonces, puede agregar explícitamente las funciones a las que desea que tenga acceso el código no confiable (lista blanca). En este caso, la secuencia de comandos del usuario solo tiene acceso a ipairs
pero nada más ( dofile
, loadfile
, etc.).
Vea Lua Sandboxes para ver un ejemplo y más información sobre lua sandboxing.
Puede utilizar la función lua_setglobal
proporcionada por la API de Lua para establecer esos valores en el espacio de nombres global en nil
que evitará efectivamente que los scripts de usuario puedan acceder a ellos.
lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "io");
lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "loadfile");
...etc...
Si estás usando Lua 5.1 prueba esto:
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
Una de las formas más fáciles de eliminar los indeseables es cargar primero un script Lua de su propia invención, que hace cosas como:
load = nil
loadfile = nil
dofile = nil
Alternativamente, puede usar setfenv
para crear un entorno restringido en el que puede insertar funciones seguras específicas.
El sandboxing totalmente seguro es un poco más difícil. Si carga código desde cualquier lugar, tenga en cuenta que el código precompilado puede bloquear a Lua. Incluso el código completamente restringido puede entrar en un ciclo infinito y bloquearse indefinidamente si no tiene un sistema para apagarlo.