在线文档教程

rexec

rexec - 受限制的执行框架

自2.6版以来已弃用:该rexec模块已在Python 3中删除。

版本2.3中更改:禁用的模块。

警告

该文档已保留,以帮助阅读使用该模块的旧代码。

该模块包含RExec类,它支持r_eval()r_execfile()r_exec(),和r_import()方法,其被限制的标准Python函数版本eval()execfile()并且execimport陈述。在此受限环境中执行的代码只能访问被视为安全的模块和功能; 您可以RExec根据需要创建子类以添加或删除功能。

警告

虽然该rexec模块设计为如下所述执行,但确实存在一些已知的漏洞,可通过仔细编写的代码进行利用。因此在需要“生产就绪”安全的情况下不应该依赖它。在这种情况下,可能需要通过子流程执行或非常仔细地“清理”代码和待处理数据。或者,rexec欢迎修补已知漏洞的帮助。

注意

RExec类可以防止代码执行像读取或写入磁盘文件,或使用TCP / IP套接字不安全的操作。但是,它不能防止使用大量内存或处理器时间的代码。

class rexec.RExec([hooks[, verbose]])

返回RExec类的一个实例。

钩子RHooks类的一个实例或它的一个子类。如果省略,或者None默认的RHooks类被实例化。无论何时rexec模块搜索模块(甚至是内置模块)或读取模块的代码,它都不会实际发送到文件系统本身。相反,它调用RHooks传递给它的构造函数或由其构造函数创建的实例的方法。(实际上,RExec对象不会进行这些调用 - 它们是由作为对象组成部分的模块加载器对象创建的,RExec这允许具有其他级别的灵活性,这在更改import受限制环境中的机制时非常有用。)

通过提供备用RHooks对象,我们可以控制文件系统对导入模块的访问,而不会改变控制访问顺序的实际算法。例如,我们可以RHooks通过一些RPC机制(如ILU)来替换一个将所有文件系统请求传递到其他文件服务器的对象。Grail的小程序加载器使用它来支持从目录的URL导入小程序。

如果verbose为true,则可以将其他调试输出发送到标准输出。

请注意,在受限环境中运行的代码仍然可以调用该sys.exit()函数,这一点很重要。要禁止退出解释程序的受限代码,请始终保护导致受限代码以捕获异常的try/ except语句运行的调用SystemExitsys.exit()从受限制的环境中删除功能是不够的 - 限制的代码仍然可以使用raise SystemExit。去除SystemExit不是一个合理的选择; 一些库代码使用这个,如果不可用,会中断。

另请参阅

Grail主页 Grail是一个完全用Python编写的Web浏览器。它使用该rexec模块作为支持Python小程序的基础,并可用作此模块的示例用法。

1. RExec对象

RExec 实例支持以下方法:

RExec.r_eval(code)

代码必须是包含Python表达式的字符串,或者是将在受限制环境的__main__模块中进行评估的编译代码对象。表达式或代码对象的值将被返回。

RExec.r_exec(code)

代码必须是包含一行或多行Python代码的字符串,或者是将在受限制环境的__main__模块中执行的编译代码对象。

RExec.r_execfile(filename)

在受限制环境的模块中执行包含在文件filename中的Python代码__main__

方法名称开头s_是类似于开头的功能r_,但代码将被授予访问I / O流的标准的限制版本sys.stdinsys.stderrsys.stdout

RExec.s_eval(code)

代码必须是包含Python表达式的字符串,它将在受限制的环境中进行评估。

RExec.s_exec(code)

代码必须是包含一行或多行Python代码的字符串,这些代码将在受限制的环境中执行。

RExec.s_execfile(code)

在受限制的环境中执行包含在文件filename中的Python代码。

RExec对象还必须支持各种方法,这些方法将在受限环境中执行的代码隐式调用。覆盖子类中的这些方法用于更改受限环境强制的策略。

RExec.r_import(modulename[, globals[, locals[, fromlist]]])

导入模块模块名称ImportError如果模块被认为是不安全的,则引发异常。

RExec.r_open(filename[, mode[, bufsize]])

open()在受限制的环境中调用when的方法。参数与那些参数相同open(),并且应该返回文件对象(或与文件对象兼容的类实例)。RExec默认行为是允许打开任何文件进行读取,但禁止任何尝试写入文件。请参阅下面的示例,了解更少限制的实现r_open()

RExec.r_reload(module)

重新加载模块对象模块,重新解析并重新初始化它。

RExec.r_unload(module)

卸载模块对象模块(将其从受限制环境的sys.modules字典中移除)。

和它们的等价物可以访问受限制的标准I / O流:

RExec.s_import(modulename[, globals[, locals[, fromlist]]])

导入模块模块名称ImportError如果模块被认为是不安全的,则引发异常。

RExec.s_reload(module)

重新加载模块对象模块,重新解析并重新初始化它。

RExec.s_unload(module)

卸载模块对象模块

2.定义受限制的环境

所述RExec类具有以下类属性,这是由所使用的__init__()方法。在现有实例上更改它们不会产生任何影响; 相反,请RExec在类定义中创建一个子类并为它们分配新值。新班级的实例将使用这些新值。所有这些属性都是字符串的元组。

RExec.nok_builtin_names

包含在受限环境中运行的程序将不可用的内置函数的名称。值RExec('open', 'reload', '__import__')。(这给出了例外,因为到目前为止,大多数内置函数都是无害的。想要重写此变量的子类可能应该从基类的值开始,并连接其他禁止函数 - 当新的危险内置函数被添加到Python中,它们也将被添加到这个模块中。)

RExec.ok_builtin_modules

包含可以安全导入的内置模块的名称。值RExec('audioop', 'array', 'binascii', 'cmath', 'errno', 'imageop', 'marshal', 'math', 'md5', 'operator', 'parser', 'regex', 'select', 'sha', '_sre', 'strop', 'struct', 'time')。关于重写此变量的类似说法也适用 - 使用基类中的值作为起点。

RExec.ok_path

包含import在受限环境中执行某个搜索时将要搜索的目录。该值RExecsys.path无限制代码中的值相同(在模块加载时)。

RExec.ok_posix_names

包含os模块中可用于在受限环境中运行的程序的功能名称。值RExec('error', 'fstat', 'listdir', 'lstat', 'readlink', 'stat', 'times', 'uname', 'getpid', 'getppid', 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')

RExec.ok_sys_names

包含sys模块中的功能和变量的名称,这些名称可用于在受限环境中运行的程序。值RExec('ps1', 'ps2', 'copyright', 'version', 'platform', 'exit', 'maxint')

RExec.ok_file_types

包含允许加载模块的文件类型。每个文件类型都是在imp模块中定义的整数常量。有意义的值是PY_SOURCEPY_COMPILEDC_EXTENSION。值RExec(C_EXTENSION, PY_SOURCE)PY_COMPILED不推荐添加子类。攻击者可以通过.pyc在文件系统中的任何位置放置一个伪造的字节编译文件()来退出受限制的执行模式,例如将其写入/tmp或上传到/incoming公用FTP服务器的目录中。

3.一个例子

让我们说,我们想要一个比标准RExec类稍宽松的政策。例如,如果我们愿意允许/tmp写入文件,我们可以继承这个RExec类的子类:

class TmpWriterRExec(rexec.RExec): def r_open(self, file, mode='r', buf=-1): if mode in ('r', 'rb'): pass elif mode in ('w', 'wb', 'a', 'ab'): # check filename: must begin with /tmp/ if file[:5]!='/tmp/': raise IOError("can't write outside /tmp") elif (string.find(file, '/../') >= 0 or file[:3] == '../' or file[-3:] == '/..'): raise IOError("'..' in filename forbidden") else: raise IOError("Illegal open() mode") return open(file, mode, buf)

注意上面的代码偶尔会禁止一个完全有效的文件名; 例如,受限环境中的代码将无法打开调用的文件/tmp/foo/../bar。为了解决这个问题,该r_open()方法将不得不简化文件名/tmp/bar,这将需要拆分文件名并对其执行各种操作。在安全受到威胁的情况下,编写简单的代码有时候会更加严格,而不是更复杂的代码,而且可能存在一个微妙的安全漏洞。