30.1. rexec-受限执行框架

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

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

Warning

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

该模块包含RExec类,该类支持r_eval()r_execfile()r_exec()r_import()方法,这是标准 Python 函数eval()execfile()以及execimport语句的受限版本。在此受限环境中执行的代码只能访问被认为安全的模块和Function;您可以将RExec子类化,以根据需要添加或删除Function。

Warning

尽管rexec模块旨在按如下所述执行,但确实存在一些已知的漏洞,可以pass精心编写的代码来利用这些漏洞。因此,在需要“生产就绪”安全性的情况下,不应依赖它。在这种情况下,可能需要pass子流程执行或非常仔细地“清理”要处理的代码和数据。另外,也欢迎提供帮助修复已知的rexec漏洞。

Note

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

pass提供备用的RHooks对象,我们可以控制对导入模块的文件系统的访问,而无需更改控制访问 Sequences 的实际算法。例如,我们可以替换RHooks对象,该对象pass某种 RPC 机制(例如 ILU)将所有文件系统请求传递到其他位置的文件服务器。 Grail 的 applet 加载器使用它来支持从目录的 URL 导入 applet。

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

请务必注意,在受限环境中运行的代码仍可以调用sys.exit()函数。要禁止受限代码退出解释器,请始终使用导致SystemExit异常的try/except语句来保护导致受限代码运行的调用。从受限环境中删除sys.exit()函数是不够的-受限代码仍可以使用raise SystemExit。删除SystemExit不是一个合理的选择;一些库代码利用了这一点,如果无法使用,则会break。

See also

  • 圣杯首页

  • Grail 是完全用 Python 编写的 Web 浏览器。它使用rexec模块作为支持 Python applet 的基础,并且可以用作该模块的示例用法。

30.1.1. RExec 对象

RExec个实例支持以下方法:

名称以s_开头的方法类似于以r_开头的函数,但是将授予该代码访问标准 I/O 流sys.stdinsys.stderrsys.stdout的受限版本的权限。

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

及其等效项,可以访问受限制的标准 I/O 流:

30.1.2. 定义受限环境

RExec类具有以下类属性,这些属性由init()方法使用。在现有实例上更改它们不会有任何效果;而是创建RExec的子类,并在类定义中为其分配新值。然后,新类的实例将使用这些新值。所有这些属性都是字符串的 Tuples。

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,这将需要拆分文件名并对其执行各种操作。在安全受到威胁的情况下,最好写一些有时过于严格的简单代码,而不是写一些更复杂并且可能带有细微安全漏洞的通用代码。

首页