【问题标题】:sanitizing a Lua table input清理 Lua 表输入
【发布时间】:2013-10-11 02:46:08
【问题描述】:

假设我想要一个由第三方提供的 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

在最坏的情况下它应该返回 nil。 这可以被认为对“普通的坏人”是安全的吗:)

【问题讨论】:

    标签: lua lua-table


    【解决方案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 在 cmets 中指出的那样,这不是阻止恶意脚本的完整解决方案。它本质上允许您将批准用于用户脚本的函数和表列入白名单。

    有关处理流氓脚本的更多信息,我会建议这个 SO 问题: Embedded Lua - timing out rogue scripts (e.g. infinite loop) - an example anyone?

    【讨论】:

    • 这并不能避免 DOS 类型的攻击:试试local script = [[local x=1;for i=1,1e100 do x=x+1 end]]
    【解决方案2】:

    我认为它不安全。试试这个:

    print(safeLoadTable [[{ foo = (function() print"yahoo" end)() } ]])
    

    编辑

    或者这个,为了更有趣:

    print(safeLoadTable [[{ foo = (function() print(os.getenv "PATH") end)() } ]])
    

    不过,我不会建议将 os.getenv 替换为 os.execute。 :-)

    这个问题不容易解决。在这种情况下,避免代码注入一点也不简单,因为您在执行此操作时正在执行一段 Lua 代码loadstring。没有简单的字符串匹配技术是真正安全的。唯一安全的方法是为 Lua 表语法的子集实现解析器,并在字符串上使用该解析器。

    顺便说一句,甚至 Lua 团队也从 Lua 5.2 中剥离了字节码验证器,因为他们发现它容易受到攻击,而且字节码是一种比 Lua 源代码简单得多的语言。

    【讨论】:

    • if (string.find(txtTable, "(", 1, true)) then return nil end
    • 但这会阻止用户将字符串放在括号中 - 你能想出一个没有那么严格的简单解决方案吗?
    • 我仍然可以打破它:print(safeLoadTable [[{ foo = print "badcode"} ]])
    【解决方案3】:

    我正是为此目的创建了 sandbox.lua。假设您的环境可以访问debug 设施,它将处理不安全的东西以及 DOS 类型的攻击。

    https://github.com/kikito/sandbox.lua

    请注意,目前它仅与 Lua 5.1 兼容。

    【讨论】:

      【解决方案4】:

      在沙盒中运行并不安全,检查源代码也不是很简单。一个想法:检查字节码!

      Emmm,其实这也不是很简单,不过这里有个懒实现:http://codepad.org/mGqQ0Y8q

      【讨论】:

      • 如果你想走这条路,试试我的bytecode inspector library
      • 我的错,我完全忘记了没有必要重新发明任何东西。
      • 没问题。重新发明轮子很有趣。
      猜你喜欢
      • 2011-08-13
      • 2018-02-18
      • 2012-10-15
      • 2011-07-27
      • 2015-11-10
      • 2018-02-22
      • 1970-01-01
      • 2015-05-21
      • 2016-11-26
      相关资源
      最近更新 更多