rexec — Система ограниченного выполнения
Устарело начиная с версии 2.6: Модуль rexec был удалён в Python 3.
Изменено в версии 2.3: Модуль отключён.
Предупреждение
Документация оставлена для помощи в чтении старого кода, использующего этот модуль.
Этот модуль содержит класс RExec, который поддерживает r_eval(), r_execfile(), r_exec(), и r_import() методы, которые являются ограниченными версиями стандартных функций Python eval(), execfile() и операторов exec и import. Код, выполняемый в этой ограниченной среде, будет иметь доступ только к модулям и функциям, которые считаются безопасными; вы можете создать подкласс RExec, чтобы добавить или удалить возможности по желанию.
Предупреждение
Хотя модуль rexec разработан для работы, как описано ниже, у него есть несколько известных уязвимостей, которые могут быть использованы тщательно написанным кодом. Поэтому его не следует использовать в ситуациях, требующих «готовых к производству» мер безопасности. В таких ситуациях может потребоваться выполнение через дочерние процессы или очень тщательное «очищение» как кода, так и данных, подлежащих обработке. Альтернативно, будут приветствоваться предложения по исправлению известных уязвимостей модуля rexec.
Примечание
Класс RExec может предотвратить выполнение кода небезопасных операций, таких как чтение или запись файлов на диске или использование сокетов TCP/IP. Однако он не защищает от кода, использующего чрезвычайно большое количество памяти или времени процессора.
-
class rexec.RExec([hooks[, verbose]]) -
Возвращает экземпляр класса
RExec.hooks — экземпляр класса
RHooksили его подкласс. Если он опущен илиNone, создаётся экземпляр по умолчанию классаRHooks. Всякий раз, когда модульrexecищет модуль (даже встроенный) или читает код модуля, он не обращается непосредственно к файловой системе. Вместо этого он вызывает методы экземпляраRHooks, который был передан или создан его конструктором. (На самом деле, объектRExecне делает эти вызовы — их делает объект загрузчика модулей, который является частью объектаRExec. Это позволяет ещё большую гибкость, что может быть полезно при изменении механикиimportв ограниченной среде.)Предоставляя альтернативный объект
RHooks, мы можем контролировать доступ к файловой системе для импорта модуля, не изменяя фактический алгоритм, который управляет порядком этих обращений. Например, мы могли бы заменить объектRHooks, который передает все запросы к файловой системе на удаленный файловый сервер по какому-либо механизму RPC, например, ILU. Загрузчик апплетов Grail использует это для поддержки импорта апплетов из URL-адреса для каталога.Если verbose имеет значение true, дополнительный отладочный вывод может быть отправлен в стандартный вывод.
Важно понимать, что код, работающий в ограниченной среде, всё ещё может вызывать функцию sys.exit(). Чтобы запретить ограниченному коду завершать интерпретатор, всегда защищайте вызовы, которые вызывают выполнение ограниченного кода, оператором try/except, который перехватывает исключение SystemExit. Удаление функции sys.exit() из ограниченной среды недостаточно — ограниченный код всё равно мог бы использовать raise SystemExit. Удаление SystemExit — не разумный вариант; некоторые библиотечные коды используют это и сломались бы, если бы оно не было доступно.
См. также
- Grail Home Page
-
Grail — это веб-браузер, написанный полностью на Python. Он использует модуль
rexecв качестве основы для поддержки Python-апплетов и может служить примером использования этого модуля.
1. Объекты RExec
Экземпляры RExec поддерживают следующие методы:
-
RExec.r_eval(code) -
code должен быть либо строкой, содержащей выражение Python, либо скомпилированным объектом кода, который будет вычислен в модуле
__main__ограниченной среды. Значение выражения или объекта кода будет возвращено.
-
RExec.r_exec(code) -
code должен быть либо строкой, содержащей одну или несколько строк Python-кода, либо скомпилированным объектом кода, который будет выполнен в модуле
__main__ограниченной среды.
-
RExec.r_execfile(filename) -
Выполнить Python-код, содержащийся в файле filename, в модуле
__main__ограниченной среды.
Методы, имена которых начинаются с s_, аналогичны функциям, начинающимся с r_, но код получит доступ к ограниченным версиям стандартных потоков ввода-вывода sys.stdin, sys.stderr, и sys.stdout.
-
RExec.s_eval(code) -
code должен быть строкой, содержащей выражение Python, которое будет вычислено в ограниченной среде.
-
RExec.s_exec(code) -
code должен быть строкой, содержащей одну или несколько строк Python-кода, которые будут выполнены в ограниченной среде.
-
RExec.s_execfile(code) -
Выполнить Python-код, содержащийся в файле filename, в ограниченной среде.
Объекты RExec также должны поддерживать различные методы, которые будут неявно вызываться кодом, выполняющимся в ограниченной среде. Переопределение этих методов в подклассе используется для изменения политик, навязанных ограниченной средой.
-
RExec.r_import(modulename[, globals[, locals[, fromlist]]]) -
Импортирует модуль modulename, вызывая исключение
ImportError, если модуль считается небезопасным.
-
RExec.r_open(filename[, mode[, bufsize]]) -
Метод, вызываемый при вызове
open()в ограниченной среде. Аргументы идентичны аргументамopen(), и должен быть возвращён объект файла (или экземпляр класса, совместимый с объектами файлов). По умолчаниюRExecразрешает открытие любого файла для чтения, но запрещает любые попытки записи в файл. См. пример ниже для реализации менее ограниченногоr_open().
-
RExec.r_reload(module) -
Перезагрузить объект модуля module, повторно проанализировав и инициализировав его.
-
RExec.r_unload(module) -
Выгрузить объект модуля module (удалить его из словаря
sys.modulesограниченной среды).
И их эквиваленты с доступом к ограниченным стандартным потокам ввода-вывода:
-
RExec.s_import(modulename[, globals[, locals[, fromlist]]]) -
Импортирует модуль modulename, вызывая исключение
ImportError, если модуль считается небезопасным.
-
RExec.s_reload(module) -
Перезагрузить объект модуля module, повторно проанализировав и инициализировав его.
-
RExec.s_unload(module) -
Выгрузить объект модуля 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в ограниченной среде. Значение дляRExecтакое же, какsys.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_SOURCE,PY_COMPILED, иC_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, что потребует разделения имени файла и выполнения различных операций с ним. В случаях, когда безопасность имеет первостепенное значение, предпочтительнее написать простой код, который иногда является чрезмерно ограниченным, вместо более общего кода, который также сложнее и может содержать скрытую уязвимость.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/rexec.html