Serialization 这安全吗?(反序列化的一种方式)

Serialization 这安全吗?(反序列化的一种方式),serialization,lua,Serialization,Lua,我想确保下面的函数是100%安全的wrt代码注入攻击。具体来说,任何人都可以找到下面函数的参数,该参数允许调用方检索包含可执行Lua代码的表,或使函数编译\exec通过函数参数传递给它的任何内容 (我采用这种非常规方法是因为在我的应用程序中,诸如co例程和调试库等内容受到限制。函数调用方将了解参数的“Function”文本键约束;请参见下文) 尝试#1:(失败/不安全) 谢谢大家的反馈。尤其是伊戈尔 根据初始反馈尝试#2。尝试#2现在还禁用字符串库元方法,例如s=“{('a'):rep(99):

我想确保下面的函数是100%安全的wrt代码注入攻击。具体来说,任何人都可以找到下面函数的参数,该参数允许调用方检索包含可执行Lua代码的表,或使函数编译\exec通过函数参数传递给它的任何内容

(我采用这种非常规方法是因为在我的应用程序中,诸如co例程和调试库等内容受到限制。函数调用方将了解参数的“Function”文本键约束;请参见下文)

尝试#1:(失败/不安全)

谢谢大家的反馈。尤其是伊戈尔

根据初始反馈尝试#2。尝试#2现在还禁用字符串库元方法,例如s=“{('a'):rep(99):find('.'):rep(99)'b')”


我找不到任何办法打破它。通过执行以下操作,可以在Lua 5.2+中获得
jail
表:

local jail = string2table("{_ENV}")[1]
但是,在运行
string2table
之后,如果向监狱表添加内容,这并不重要,因为每次都会生成一个新的监狱表。(只是不要重复使用桌子!)

然而,我认为我对Lua沙箱不太了解,不足以宣布它是安全的。可能有些事情我忽略了


也可以考虑替换<代码>字符串。查找(s,{)=1 < /COD>用<代码> String。子(s,1, 1)~=“{”/代码>。这样你就不必搜索整个字符串来检查第一个字符是否是一个开放括号。

允许包含“函数”的标识符作为子串:<代码> String。GSUB(S),“%F[%WY]函数%F[^ %WY]”,“fun\\99tion”)示例:
string2table(“{functional=true}”)
一些输入字符串可能会挂起您的Lua VM:
string2table({('a'):rep(99):find('.'''''.'):rep(99)'b'))
此外,IIRC恶意字节码也可能会导致解释器出现问题,因此您需要确保只加载源代码。有一个想法:为了降低风险,为什么不接受JSON而不是Lua表字符串,并使用现有的JSON解析库之一?这将解决表中存在表达式的任何问题键或值,因为JSON中只允许文本值。
--[[ string2table(s : string)

De-serialise the string argument into a Lua table.

s should define a string serialised Lua constructor

However, no value of s can:
    embed any code that can be executed at any stage by the caller
    cause a runtime error during exec of the function

Pre:
    Requires Lua v5.3
    string2table() is in the global env.
    The caller has no acccess to load or pcall. i.e the caller is in a jail
    Assumes the string library is present/visible.

    s should represent a serialised Lua constructor as a string starting with "{".
    s cannot not be pre-compiled or the function will return an error.
    s must not encode any table key containing the text "function".

Warning:
    Inefficient (invokes Lua compiler).
        Recommend JSON & JSON lib for frequent use over this function.

Return Value:

    On success

        table : s de-serialised into a lua table. Bascially pcall(load(s))

    On fail

        nil, errmsg
]]

do

    local s_load         = load
    local string_mt      = getmetatable("")

    function string2table(s)
        if type(s) ~= "string" then return nil, "call format: string2table(string)" end
        if string.find(s, "{") ~= 1 then return nil, "string arg must begin with '{'" end -- just a hint, this affords no protection
        s = "return"..string.gsub(s, "function", "fun\\99tion")     -- NB   \99 = "c"
        -- The return & gsub above prevents embedding most code from being embedded in s.
        -- Specifically re the gsub:
        --      when the text 'function' appears in a lua string it gets converted to 'function' ie no effect.
        --      when the text 'function' appears outside of a lua string it gets converted to 'fun\99tion' causing the pcall to fail.
        -- The cost of the gsub aprroach is that s can't define any table key with the text "function" in it.
        -- However any "function" text embedded in a string will be unaffected.

        -- gsub option:    string.gsub(s, "%f[%w_]function%f[^%w_]", "fun\\99tion")
        -- This variation above should safely allows keys with ..'function'.. in the key text to still load e.g. "{functional = true}"
        -- [ed: I simply havent used this alt. gsub yet because im still learning Lua patterns and %f still confuses me]

        local jail = {}

        local f, err = s_load(s, "string2table:", "t", jail) -- "t" means only text chunks
        if err then return nil, err end   -- it didnt compile, return the error

        -- The string library's metatable represents a gaping hole in the jail. Temporarily close it.
        -- This will ensure strings like this "{('a'):rep(99):find(('.*'):rep(99)..'b')}" are caught as an error.
        string_mt.__index = nil -- disable string lib metatable

        local ok, torErrmsg = pcall(f)

        string_mt.__index = string
        if not ok then return nil, torErrmsg end -- runtime error occured
        return torErrmsg -- all ok, return the table
    end
end

--[[ quick test cases:

    "{s = \"function\"}"                                            -- rv = true, {s = "function"}
    "{f = (function () while true do end end)()}"                   -- value is a function call; rv = nil, [string "luaDoStringLua:simple"]:1: ')' expected near '\'
    "{[(function () while true do end return 123 end)()] = 456}"    -- key is a function call;   rv = nil, [string "luaDoStringLua:simple"]:1: ')' expected near '\'
    "{a = t.IdontExist}"                                            -- runtime error; rv = nil, [string "luaDoStringLua:simple"]:1: attempt to index a nil value (global 't')
    "{('a'):rep(99):find(('.*'):rep(99)..'b')}"                     -- If string if exec'd it will hang the Lua interpreter.
]]
local jail = string2table("{_ENV}")[1]