0Pricing
Lua Academy · 课时

构建受限沙箱

创建安全的 _ENV 白名单,并使用 load() 执行不受信任的代码。

构建受限沙箱 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

目标

受限沙箱可以安全地运行不受信任的 Lua 代码:代码可以进行计算、使用字符串和数学函数,但不能访问文件系统、OS 或网络。

白名单方案

从头构建沙箱环境,只加入安全且行为明确的函数。

local function makeSandbox()
  return {
    print   = print,
    type    = type,
    tostring = tostring,
    tonumber = tonumber,
    pairs   = pairs,
    ipairs  = ipairs,
    next    = next,
    select  = select,
    unpack  = table.unpack,
    error   = error,
    pcall   = pcall,
    xpcall  = xpcall,
    math    = math,
    string  = { format=string.format, find=string.find,
                match=string.match, gmatch=string.gmatch,
                gsub=string.gsub, sub=string.sub,
                len=string.len, byte=string.byte, char=string.char },
    table   = { insert=table.insert, remove=table.remove,
                concat=table.concat, sort=table.sort,
                unpack=table.unpack, move=table.move },
  }
end

在沙箱中运行代码

以沙箱作为代码的 _ENV,加载并执行用户代码。

local function runSandboxed(code, env)
  local fn, err = load(code, "user", "t", env)
  if not fn then return nil, err end
  return pcall(fn)
end
local env = makeSandbox()
local ok, err = runSandboxed("return 1+1", env)
print(ok, err)  -- true  2

捕获输出

将 print 替换为自定义函数,使其追加到缓冲区,而不是写入标准输出。

local output = {}
env.print = function(...)
  local parts = {}
  for i = 1, select("#", ...) do
    parts[i] = tostring(select(i, ...))
  end
  output[#output+1] = table.concat(parts, "\t")
end

返回值

如果要允许沙箱代码返回值,请将编译后的代码块作为函数调用,并捕获其返回值。

local fn = load("return math.sqrt(144)", "user", "t", env)
if fn then
  local ok, result = pcall(fn)
  print(ok, result)  -- true  12.0
end

阻止元方法漏洞利用

沙箱代码不应获得对元表或 rawget/rawset 的引用,以免绕过字段限制。

限制字符串长度

请重写字符串操作,以限制输出长度,并防止通过分配超大字符串发动 DoS 攻击。

使用 debug.sethook 限制资源

添加指令计数钩子,以终止失控的代码。

local function sandboxWithLimit(code, env, maxOps)
  local ops = 0
  debug.sethook(function()
    ops = ops + 1
    if ops > maxOps then error("Instruction limit exceeded") end
  end, "", 100)
  local result = table.pack(runSandboxed(code, env))
  debug.sethook()
  return table.unpack(result, 1, result.n)
end

测试沙箱

编写测试,尝试已知的逃逸途径:访问 _G、调用 load、使用 debug,并确认这些尝试都会失败。

已知逃逸途径

常见的逃逸路径包括:string.rep("x",2^30)(内存 DoS)、标准对象上的 ({}).__index、通过字符串元表访问 debug,以及通过 package.loaded 访问 io。

沙箱问题

为什么沙箱不包含 load 或 dofile?

回顾:构建受限沙箱

在自定义 env 表中只加入安全函数。使用 load(code, name, "t", env)。通过 debug.sethook 添加指令计数。测试逃逸途径。绝不能包含 load、dofile、debug 或全局表访问。

常见问题解答

「构建受限沙箱」课时是免费的吗?

是的 — 「构建受限沙箱」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「构建受限沙箱」这节课中我会学到什么?

创建安全的 _ENV 白名单,并使用 load() 执行不受信任的代码。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「构建受限沙箱」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Lua 5.2+ 中的 _ENV 模型
  2. 构建受限沙箱
  3. 防止沙箱逃逸
  4. 资源限制和检测
← 返回 Lua Academy