Я хочу прикрепить функциональные заглушки к написанному мною процессу обработки данных, и было бы удобно иметь возможность применять их через файл конфигурации.
Я могу загрузить и запустить их с помощью функции eval
, но хочу иметь возможность управлять доступным «песочницей» пространства имен, в которой могут работать оцениваемые функции, чтобы избежать внедрения вредоносного кода.
В документации по python предлагается отключить __builtins__
и затем заполнить глобальные и локальные (или это оба? Неясно) глобальные и локальные объекты как словари, содержащие объекты в пространстве имен выполнения.
Когда я делаю это, код, который я успешно выполнял, перестает работать.
Я думаю это потому, что одна из моих тестовых лямбда-ссылок ссылается на функции, обычно импортируемые из модуля datetime
- но мне не ясно, как заставить их успешно присоединиться к пространству имен.
from datetime import datetime
now = datetime.now()
lambdas = { "Report Date" : "lambda x : now.strftime(\"%d/%m/%Y\")",
"Scary Test" : "lambda x : os.curdir " }
compiled_funcs = {k:eval(v) for k,v in lambdas.items()}
compiled_funcs ['Report Date'](1)
>>> '15/04/2019'
compiled_funcs ['Scary Test'](1)
>>> '.'
Теперь я хочу отредактировать функцию eval()
, чтобы ограничить доступную область видимости, чтобы функция datetime продолжала работать, но модуль os
не работает (если я могу вызвать команду os, я мог бы сделать что-то пугающее как протереть диск или еще хуже)
Я пробовал такие конструкции, как:
compiled_funcs = {k:eval(v,{'__builtins__':None, "now" : now, "datetime" : datetime, } , { }) for k,v in lambdas.items()}
Но когда я это делаю, я получаю следующую ошибку:
AttributeError: 'NoneType' object has no attribute '__import__'
Что говорит о том, что где-то / каким-то образом функция, которую я хочу применить, пытается вызвать / импортировать некоторый контент по линии - и (предположительно) это правильно блокируется из-за того, что он заблокировал содержимое __builtins__
. Есть ли способ предварительно упаковать такие функции и внедрить их в глобальные переменные eval или словари localals для включения предопределенного набора функциональных инструментов?
Как только я получу эту работу, я смогу расширить ее, чтобы я мог курировать свое собственное подмножество безопасных вызовов функций, которые будут доступны для этой коллекции во время выполнения из файлов конфигурации.
N.B. Я знаю, что выше, я мог бы определить свой lambdæ без аргументов - но в моем реальном коде было бы нормально передать один параметр, поэтому я соответственно построил свой тестовый код.