On this page
30.1. rexec-受限执行框架
自 2.6 版起弃用:rexec模块已在 Python 3 中删除。
在版本 2.3 中更改:禁用模块。
Warning
该文档已保留在原处,以帮助您阅读使用该模块的旧代码。
该模块包含RExec类,该类支持r_eval()
,r_execfile()
,r_exec()
和r_import()
方法,这是标准 Python 函数eval(),execfile()以及exec和import语句的受限版本。在此受限环境中执行的代码只能访问被认为安全的模块和Function;您可以将RExec子类化,以根据需要添加或删除Function。
Warning
Note
RExec类可以防止代码执行不安全的操作,例如读取或写入磁盘文件或使用 TCP/IP 套接字。但是,它不能防止使用大量内存或处理器时间的代码。
-
- class *
rexec.
RExec
([* hooks * [,* verbose *]])
- 返回RExec类的实例。
- class *
- hooks *是
RHooks
类或其子类的实例。如果Ellipsis或None
,则实例化默认的RHooks
类。每当rexec模块搜索模块(甚至是内置模块)或读取模块的代码时,它实际上都不会访问文件系统本身。相反,它调用传递给其构造函数或由其构造函数创建的RHooks
实例的方法。 (实际上,RExec对象不会进行这些调用-它们是由RExec对象的一部分的模块加载器对象进行的。这提供了另一种灵 Active,这在受限环境中更改import的机制时很有用。 )
pass提供备用的RHooks
对象,我们可以控制对导入模块的文件系统的访问,而无需更改控制访问 Sequences 的实际算法。例如,我们可以替换RHooks
对象,该对象pass某种 RPC 机制(例如 ILU)将所有文件系统请求传递到其他位置的文件服务器。 Grail 的 applet 加载器使用它来支持从目录的 URL 导入 applet。
如果* verbose *为 true,则可能会将其他调试输出发送到标准输出。
请务必注意,在受限环境中运行的代码仍可以调用sys.exit()函数。要禁止受限代码退出解释器,请始终使用导致SystemExit异常的try/except语句来保护导致受限代码运行的调用。从受限环境中删除sys.exit()函数是不够的-受限代码仍可以使用raise SystemExit
。删除SystemExit不是一个合理的选择;一些库代码利用了这一点,如果无法使用,则会break。
30.1.1. RExec 对象
RExec个实例支持以下方法:
RExec.
r_eval
(* code *)-
- code *必须是包含 Python 表达式的字符串或已编译的代码对象,将在受限环境的main模块中对其进行评估。表达式或代码对象的值将被返回。
-
RExec.
r_exec
(* code *)-
- code *必须是包含一行或多行 Python 代码的字符串,或者是将在受限环境的main模块中执行的已编译代码对象。
-
RExec.
r_execfile
(* filename *)- 执行受限环境的main模块中文件* filename *中包含的 Python 代码。
名称以s_
开头的方法类似于以r_
开头的函数,但是将授予该代码访问标准 I/O 流sys.stdin
,sys.stderr
和sys.stdout
的受限版本的权限。
RExec.
s_eval
(* code *)-
- code *必须是包含 Python 表达式的字符串,它将在受限环境中进行评估。
-
RExec.
s_exec
(* code *)-
- code *必须是包含一行或多行 Python 代码的字符串,该代码将在受限环境中执行。
-
RExec.
s_execfile
(* code *)- 在受限环境中执行文件* filename *中包含的 Python 代码。
RExec对象还必须支持各种方法,这些方法将在受限环境中执行的代码隐式调用。在子类中重写这些方法用于更改由受限环境强制实施的策略。
RExec.
r_import
(* modulename * [,* globals * [,* locals * [,* fromlist *]]])- 导入模块* modulename *,如果认为模块不安全,则引发ImportError异常。
RExec.
r_open
(* filename * [,* mode * [,* bufsize *]])RExec.
r_reload
(* module *)- 重新加载模块对象* module *,重新解析并重新初始化它。
RExec.
r_unload
(* module *)- 卸载模块对象* module *(将其从受限环境的
sys.modules
字典中删除)。
- 卸载模块对象* module *(将其从受限环境的
及其等效项,可以访问受限制的标准 I/O 流:
RExec.
s_import
(* modulename * [,* globals * [,* locals * [,* fromlist *]]])- 导入模块* modulename *,如果认为模块不安全,则引发ImportError异常。
RExec.
s_reload
(* module *)- 重新加载模块对象* module *,重新解析并重新初始化它。
RExec.
s_unload
(* module *)- 卸载模块对象* module *。
30.1.2. 定义受限环境
RExec类具有以下类属性,这些属性由init()方法使用。在现有实例上更改它们不会有任何效果;而是创建RExec的子类,并在类定义中为其分配新值。然后,新类的实例将使用这些新值。所有这些属性都是字符串的 Tuples。
RExec.
nok_builtin_names
- 包含内置函数的名称,这些名称对于在受限环境中运行的程序将不可用。 RExec的值为
('open', 'reload', '__import__')
。 (这是个 exception,因为到目前为止大多数内置函数都是无害的.要覆盖此变量的子类可能应该以 Base Class 中的值开头,并连接其他禁止的函数-当新的危险内置函数时被添加到 Python,它们也将被添加到此模块.)
- 包含内置函数的名称,这些名称对于在受限环境中运行的程序将不可用。 RExec的值为
RExec.
ok_builtin_modules
- 包含可以安全导入的内置模块的名称。 RExec的值为
('audioop', 'array', 'binascii', 'cmath', 'errno', 'imageop', 'marshal', 'math', 'md5', 'operator', 'parser', 'regex', 'select', 'sha', '_sre', 'strop', 'struct', 'time')
。关于覆盖此变量的类似说明也适用-使用 Base Class 中的值作为起点。
- 包含可以安全导入的内置模块的名称。 RExec的值为
RExec.
ok_path
RExec.
ok_posix_names
RExec.
ok_sys_names
RExec.
ok_file_types
30.1.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
,这将需要拆分文件名并对其执行各种操作。在安全受到威胁的情况下,最好写一些有时过于严格的简单代码,而不是写一些更复杂并且可能带有细微安全漏洞的通用代码。