如何从C API在自己的环境中执行不受信任的Lua文件

我想通过调用lua_setfenv()在自己的环境中执行不受信任的.lua文件,这样它就不会影响我的任何代码。

该function的文档虽然只解释了如何调用函数,而不是如何执行文件。

目前运行我使用的文件:

int error = luaL_loadfile(mState, path.c_str()) || lua_pcall(mState, 0, 0, 0); 

我是否必须使用lua_setfenv从C API调用“dofile”lua函数,还是有更优雅的方法呢?

请参阅Lua用户的沙盒维基的讨论,以及脚本安全性的更一般主题。 这种事情有许多细微而不那么微妙的问题。 它可以完成,但是对于诸如for i=1,1e39 do end代码的保护for i=1,1e39 do end需要的不仅仅是限制沙箱可用的function。

一般技术是为沙箱创建一个function环境,其中包含允许function的白名单。 在某些情况下,该列表甚至可能是空的,但是让用户有权访问pairs() ,这几乎肯定是无害的。 沙箱页面包含系统function列表,这些function按其安全性细分,作为构建此类白名单的便捷参考。

然后使用lua_setfenv()将函数环境应用于您加载(但尚未执行)的用户脚本,并使用lua_loadfile()lua_loadstring() 。 附加环境后,您可以使用lua_pcall()和朋友执行它。 在执行之前,有些人实际扫描了加载的字节码以查找他们不想允许的操作。 这可以用于绝对禁止循环或写入全局变量。

另一个注意事项是加载函数通常会加载预编译的字节码或Lua文本。 如果你从不允许预编译的字节码,那么结果会更加安全,因为已经发现许多使行为不正常的方法都依赖于手工制作无效的字节码。 由于字节码文件以明确定义的非ASCII文本字节序列开头,所以您需要做的就是将脚本读入字符串缓冲区,测试标记的lua_loadstring() ,并将其传递给lua_loadstring()如果它不是字节码。

多年来,在Lua-L邮件列表中进行了相当多的讨论,因此在那里搜索也可能会有所帮助。

顺便说一句,这就是我最终做的事情:

 /* Loads, compiles and executes an unstrusted file. */ bool Lua::RunUntrustedFile(const string& path) { if(luaL_loadfile(mState, path.c_str())) { ErrorLog(lua_tostring(mState, 1)); Pop(1); return false; } Lua::SetMaximumInstructions(100000000); lua_newtable(mState); lua_setglobal(mState, "upload"); ASSERT(Lua::GetStackSize() == 1); lua_getglobal(mState, "upload"); ASSERT_ALWAYS(lua_setfenv(mState, 1) != 0); ASSERT(Lua::GetStackSize() == 1); if(lua_pcall(mState, 0, 0, 0)) { Lua::ClearMaximumInstructions(); ErrorLog(lua_tostring(mState, -1)); Pop(1); return false; } ASSERT(Lua::GetStackSize() == 0); Lua::ClearMaximumInstructions(); return true; } 

“支持”function:

 static void Pop(int elements = 1) { lua_pop(mState, elements); } /* Sets a maximum number of instructions before throwing an error */ static void SetMaximumInstructions(int count) { lua_sethook(mState, &Lua::MaximumInstructionsReached, LUA_MASKCOUNT, count); } static void ClearMaximumInstructions() { lua_sethook(mState, &Lua::MaximumInstructionsReached, 0, 0); } static void MaximumInstructionsReached(lua_State *, lua_Debug *) { Error("The maximum number of instructions has been reached"); } static int GetStackSize() { return lua_gettop(mState); } 

luaL_loadfile()将加载块,然后调用lua_setfenv()来设置环境表,然后调用lua_pcall()来执行块。 请参阅Maygarden法官最近给出的答案。 来自.lua使用句柄调用lua函数?