假设我想要一个Lua表,它将从第三方提供,而不是完全可靠,来自文件或其他IO源。
我将表格作为字符串,例如“{['valid'] = 10}”,我可以将其加载为
externalTable = loadstring("return " .. txtTable)()
但这会打开代码注入的漏洞,即:txtTable = os.execute('rm -rf /')
所以我做了这个消毒功能:
function safeLoadTable(txtTable)
txtTable = tostring(txtTable)
if (string.find(txtTable, "(", 1, true))
then return nil end
local _start = string.find(txtTable, "{", 1, true)
local _end = string.find(string.reverse(txtTable), "}", 1, true)
if (_start == nil or _end == nil)
then return nil end
txtTable = string.sub(txtTable, _start, #txtTable - _end + 1)
print("cropped to ", txtTable)
local pFunc = loadstring("return " .. txtTable)
if (pFunc) then
local _, aTable = pcall(pFunc)
return aTable
end
end
在最坏的情况下,它应该返回零。 这可以被认为是安全的,反对“常规的恶意人”:)
答案 0 :(得分:1)
我认为这不安全。试试这个:
print(safeLoadTable [[{ foo = (function() print"yahoo" end)() } ]])
修改强>
或者这个,为了更多的乐趣:
print(safeLoadTable [[{ foo = (function() print(os.getenv "PATH") end)() } ]])
尽管如此,我还是不建议将os.getenv
替换为os.execute
。 : - )
问题不容易解决。在这种情况下,代码注入避免并不简单,因为在执行loadstring
时您正在执行一段Lua代码。没有简单的字符串匹配技术真的很安全。唯一安全的方法是为Lua表语法的子集实现解析器,并在字符串上使用该解析器。
答案 1 :(得分:1)
您可以在沙箱中运行不安全的代码。
以下是一个简单的沙盒在Lua 5.1中的外观(为简洁省略了错误处理):
local script = [[os.execute("rm -rf /")]]
local env = { print=print, table=table, string=string }
local f, err = loadstring(script)
if err then
-- handle syntax error
end
setfenv(f, env)
local status, err = pcall(f)
if not status then
-- handle runtime error
end
在Lua 5.2中,您可以使用load
函数将脚本加载到自己的环境中。
结果将是从pcall
返回的运行时错误:
attempt to index global 'os' (a nil value)
修改强>
正如Lorenzo Donati在评论中指出的那样,这不是阻止流氓脚本的完整解决方案。它基本上允许您列出批准用户脚本的函数和表。
有关处理流氓脚本的更多信息,我建议这个问题: Embedded Lua - timing out rogue scripts (e.g. infinite loop) - an example anyone?
答案 2 :(得分:1)
我正是为了这个目的创建了sandbox.lua。假设您的环境可以访问debug
工具,它将处理不安全的东西以及DOS类型的攻击。</ p>
https://github.com/kikito/sandbox.lua
请注意,目前仅与Lua 5.1兼容。
答案 3 :(得分:0)
在沙箱中运行并不安全,检查源代码并不是很简单。一个想法:检查字节码!
嗯,实际上这也不是很简单,但这是一个懒惰的实现:http://codepad.org/mGqQ0Y8q