Отключить импорт встроенных модулей в embedded Python



Я встраиваю Python 3.6 в свое приложение, и я хочу отключить команду импорта в скриптах, чтобы запретить пользователям импортировать любые встроенные библиотеки python. Я хотел бы использовать только сам язык и мои собственные c++ определенные модули.



Py_SetProgramName (L"Example");
Py_Initialize ();
PyObject* mainModule = PyImport_AddModule ("__main__");
PyObject* globals = PyModule_GetDict (mainModule);

// This should work
std::string script1 = "print ('example')";
PyRun_String (script1.c_str (), Py_file_input, globals, nullptr);

// This should not work
std::string script2 = "import randomn"
"print (random.randint (1, 10))n";
PyRun_String (script2.c_str (), Py_file_input, globals, nullptr);

Py_Finalize ();


Знаете ли вы какой-нибудь способ достичь этого?

708   1  

1 ответ:

Python имеет долгую историю невозможности создать безопасную песочницу (см. Как я могу создать песочницу Python в чистом Python? в качестве отправной точки, а затем погрузитесь в старую дискуссиюpython-dev , Если вам так хочется). Вот то, что я считаю вашими лучшими двумя вариантами.

Предварительное сканирование кода

Прежде чем что-либо выполнять, просканируйте код. Вы можете сделать это в Python с помощью модуляAST , а затем пройти по дереву или, скорее всего, достаточно далеко с помощью более простой текстовый поиск. Это, вероятно, работает в вашем сценарии, потому что у вас есть ограниченные варианты использования - он не обобщается на действительно произвольный код.

То, что вы ищете в вашем случае, будет любыми import утверждениями (легко) и любыми переменными верхнего уровня (например, в a.b.c вы заботитесь о a и вероятно a.b для данного a), которые не "одобрены". Это позволит вам потерпеть неудачу на любом коде, который не является чистым перед его запуском.

Проблема здесь в том, что даже тривиально запутанный код будет обходить ваши проверки. Например, вот несколько способов импорта модулей, заданных другими модулями или глобалами, которые не будут найдены при базовом сканировании import. Скорее всего, вы захотите ограничить прямой доступ к __builtins__, globals, некоторые/большинство / все имена с __double_underscores__ и члены определенных типов. В AST они неизбежно будут отображаться как чтение переменных верхнего уровня или доступ к атрибутам.

getattr(__builtins__, '__imp'+'ort__')('other_module')

globals()['__imp'+'ort__']('other_module')

module.__loader__.__class__(
    "other_module",
    module.__loader__.path + '/../other_module.py'
).load_module()

(я надеюсь, что это само собой разумеется, это невыполнимая задача, и почему такой подход к песочнице так и не добился полного успеха. Но это может быть достаточно хорошо, в зависимости от вашей конкретной модели угрозы.)

Аудит времени выполнения

Если вы в состоянии скомпилировать свою собственную среду выполнения Python, вы можете рассмотреть возможность использования (в настоящее время черновик) PEP 551 Крюков. (Отказ от ответственности: я являюсь автором этого PEP.) Есть проекты реализаций против последних 3.7 и еще 3.6 выпуски.

По сути, это позволит вам добавить крючки для ряда события внутри Python и определяют, как реагировать. Например, вы можете прослушивать все события import и определять, разрешать или не разрешать их во время выполнения, основываясь на том, какой именно модуль импортируется, или прослушивать события compile для управления всеми компиляциями во время выполнения. Это можно сделать из кода Python (с помощью sys.addaudithook) или C-кода (с помощью PySys_AddAuditHook).

The Programs/spython.файл c в РЕПО является довольно подробным примером аудита из C, в то время как выполнение его из Python выглядит более похоже на это (взято из моего выступления Об этом PEP):

import sys

def prevent_bitly(event, args):
    if event == 'urllib.Request' and '://bit.ly/' in args[0]:
        print(f'WARNING: urlopen({args[0]}) blocked')
        raise RuntimeError('access to bit.ly is not allowed')

sys.addaudithook(prevent_bitly)
Недостатком этого подхода является то, что вы должны создавать и распространять свою собственную версию Python, а не полагаться на установку системы. Тем не менее, в целом это хорошая идея, если ваше приложение зависит от внедрения, поскольку это означает, что вам не придется принуждать пользователей к определенной конфигурации системы.

Comments

    Ничего не найдено.