Lua 函数重定义,以及安全的运行时环境(沙盒)

  本文章借鉴《Lua程序设计(第四版)》。

一、函数重定义

  在Lua中,由于函数可以被保存在普通变量中,因此在Lua语言中可以轻松地重新定义函数,甚至是预定义函数。这种机制也正是Lua语言灵活的原因之一。通常,当重新定义一个函数的时候,我们需要在新的实现中调用原来的那个函数。例如,假设要冲i性能定义函数sin以使其参数以角度为单位而不是以弧度为单位。那么这个新函数就可以先对参数进行转换,然后调用原来的sin函数进行真正的计算。代码可能形如:

print(math.pi)			--> 3.1415926535898
print(math.sin(30 * (math.pi / 180))) --> 0.5

local oldSin = math.sin
math.sin = function(x)
	return oldSin(x * (math.pi / 180))
end

print(math.sin(30))			  --> 0.5

  另一种更清晰的完成重新定义的写法是:

print(math.sin(30 * (math.pi / 180))) --> 0.5

do
	local oldSin = math.sin
	local k = math.pi / 180
	math.sin = function(x)
		return oldSin(x * k)
	end
end

print(math.sin(30))			  --> 0.5

  上述代码使用了do代码段来限制局部变量oldSin的作用范围;根据可见性规则,局部变量oldSin只在这部分代码段中有效。因此,只有新版本的函数sin才能访问原来的sin函数,其他部分代码则访问不了。

二、沙盒

  将老版本的函数保存在一个私有的变量中,只用新版本的函数才能访问它,这样的技术创建一个安全的运行环境,即所谓的 “沙盒(sandbox)”。
  我们可以使用同样的技巧来创建安全的运行时环境(secure environment),即所谓的沙盒。当执行一些诸如从远程服务器上下载到的未受信任代码(untrusted code)时,安全的运行时环境非常重要。例如,我们可以通过使用闭包(closure)重定义函数 io.open 来限制一个程序能够访问的文件:

do
	local oldOpen = io.open
	local access_OK = function(filename, mode)
		-- check access
	end
	io.open = function(filename,mode)
		if access_OK(filename, mode) then
			return oldOpen(filename, mode)
		else
			return nil, "access denied"
		end
    end
end

  上述代码的巧妙之处在于,在经过重新定义后,一个程序只能通过新的受限版本来调用原来未受限版本的 io.open 函数。示例代码将原来不安全的版本保存为闭包的一个私有变量,该变量无法从外部访问。通过这一技巧,就可以在保证简洁性和灵活性的前提下在Lua语言本身上构建Lua沙盒。
  相对于提供一套大而全(one-size-fits-all)的解决方案,Lua语言提供的是一套 “元机制(meta-mechanism)”,借助这种机制可以根据特定的安全需求来裁剪具体的运行时环境(真实的沙盒除了保护外部文件还有更多的功能)。

你可能感兴趣的:(#,Lua)