创建一个安全的 Lua 沙箱..?
Posted
技术标签:
【中文标题】创建一个安全的 Lua 沙箱..?【英文标题】:Creating a secure Lua sandbox..? 【发布时间】:2016-03-27 02:11:01 【问题描述】:现在我正在做很多事情。
local env =
print = print,
setfenv(函数,环境) 然后使用元方法来锁定Instances上的属性,但它确实效率低下并且有很多绕过。我用谷歌搜索了它,我发现的一切都与此相同:无法正常工作。
【问题讨论】:
您指的是什么“绕过”?沙盒意味着脚本只能访问您明确允许的内容。鉴于您显示的代码,func
将只能访问 print
以及您调用它时使用的任何参数。
“假设我也想授予对 getfenv() 的访问权限。”如果你不希望人们走进你的家,你就不要给他们钥匙。这里也是如此:如果您不希望人们突破沙盒,不要给他们这样做的工具。所以任何好的沙盒都会阻止你使用getfenv
。
@Nicol 但更好的沙箱将允许沙箱化访问任何东西。当我想到沙盒时,我认为它就像是我自己的微型世界,在那里我可以安全地做事,而无需访问“父环境”。例如 getfenv(2) 会出错,因为“父环境”不存在。 (确实如此,但这不应该从沙箱内部看到。)
所以我认为对你的比喻的改进是如果你不希望人们走进你的家,不要告诉他们它在哪里。
我不用担心字节码; ROBLOX 已将其删除。
【参考方案1】:
在 Lua 5.1 中,沙盒非常简单。如果您在某处的某个文件中有 Lua 脚本,并且您希望阻止它访问任何函数或您提供的参数以外的任何内容,您可以这样做:
local script = --Load the script via whatever means. DO NOT RUN IT YET!
setfenv(script, )
script
现在被沙盒化了。它不能访问您直接提供的值以外的任何内容。它创建的函数无法访问此沙盒环境之外的任何内容。您原来的全局环境与它们完全隔绝,除了您允许它访问的内容。
显然你可以在那个桌子上放任何你喜欢的东西;该表将包含您喜欢的任何全球可访问的东西。您可能应该让 Lua 脚本访问基本的 Lua 标准库函数;其中大部分是纯函数,不会做任何不愉快的事情。
如果您想保持沙箱的完整性,以下是您不得授予用户访问权限的 Lua 标准库内容列表:
getfenv
。用户有正当理由可以setfenv
,以便它可以在您的沙箱中创建自己的迷你沙箱。但是,如果您想维护沙盒的完整性,则不能允许访问您放入沙盒中的任何函数的环境。
getmetatable
:同上推理;设置元表是可以的。虽然恶意代码可以通过更改元表来破坏对象,但恶意代码可以通过执行无限循环来破坏整个系统。
整个 debug
库。通过调试库,各种诡计都是可能的。
您显然还需要解决this problem that Lua 5.1 has with loading bytecode from within a Lua script。这可以用来打破沙盒。不幸的是,Lua 5.1 并没有很好的工具。在 Lua 5.2+ 中,您可以封装load
和loadfile
,这样无论用户提供什么,您都可以在内部传递“t”作为模式参数。但是在 Lua 5.1 中,你需要一些方法来封装 load
et.al。这样您就可以分辨出数据何时是文本,何时不是。通过阅读 Lua 源代码,您可能会找到 Lua 用来区分字节码和文本的代码。
或者您可以完全禁止 load
及其朋友。
如果您想阻止用户对系统做丑陋的事情,请禁用 os
和 io
库。
【讨论】:
我可能值得一提的是,在“不得授予访问权限”部分禁用loadstring
或至少使用loadstring
加载字节码:gist.github.com/corsix/6575486
@PaulKulchenko:感谢您的来信。我假设 LuaJIT 没有这个特定问题,因为使用了不同的字节码格式(尽管可能使用 LuaJIT 字节码来破坏沙箱)。
@NicolBolas 你的意思是这样吗? corsix.org/content/malicious-luajit-bytecode ;-) 没有加载库。 (除了 jit(用于 jit 编译),但它没有在代码中引用/使用。)对于任何类型的沙箱,请确保避免所有字节码加载。
除非您在操作系统级别设置时间限制,否则应该删除或限制的另一件事是访问字符串库的模式匹配函数(并记住字符串上的元表!)。 (debug.sethook
for abort 无济于事,您需要停止长时间运行的 C 函数。)示例:function slow(i) return ("a"):rep(i):match(("a+"):rep(i-1)..'a') end
– slow( 26 )
在我的计算机上大约需要 1.5 秒,每增加一倍时间就会加倍。 (所以slow(64)
已经运行了大约 13k 年……)
getmetatable
可以暴露给沙箱,只要您不希望沙箱代码有权访问的元表具有非零 __metatable
字段。以上是关于创建一个安全的 Lua 沙箱..?的主要内容,如果未能解决你的问题,请参考以下文章