Python - Создание скриптовой системы

Я создаю приложение wxpython, которое я скомпилирую с помощью различных утилит замораживания, чтобы создать исполняемый файл для нескольких платформ.

программа будет редактором карт для тайлового игрового движка

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

Я хочу, чтобы система так работала.

пользователь поместит скрипт Python, который он хочет запустить, в стилизованное текстовое поле, а затем нажмите кнопку, чтобы выполнить скрипт.

Я хорошо разбираюсь в этом, это все действительно простые вещи. получить скрипт из текстового поля в виде строки, скомпилировать его в объект cod с помощью встроенной функции compile (), затем выполнить скрипт со статусом exec

script = textbox.text #bla bla store the string
code = compile(script, "script", "exec") #make the code object
eval(code, globals())

дело в том, что я хочу убедиться, что эта функция не может вызвать никаких ошибок или ошибок,
скажите, есть ли в сценарии оператор импорта. вызовет ли это какие-либо проблемы, учитывая, что код был скомпилирован с чем-то вроде py2exe или py2app?
как мне убедиться, что пользователь не может нарушить критическую часть программы, например, изменить часть графического интерфейса, но при этом разрешить их для изменения данных проекта (данные хранятся в глобальных свойствах в собственном модуле)? Я думаю, что это означало бы изменить глобальный dict, который передается функции eval.
как мне убедиться, что этот eval не может вызвать зависание программы из-за длинного или бесконечного цикла? как мне убедиться, что ошибка, возникшая в коде пользователя, не может привести к сбою всего приложения?

в основном, как мне избежать всех тех проблем, которые могут возникнуть, когда пользователь может запускать свой собственный код?

РЕДАКТИРОВАТЬ: Относительно полученных ответов

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

на самом деле мне все равно, если они это сделают. Меня больше беспокоит, что кто-то непреднамеренно сломает то, о чем они не знали. если бы кто-то действительно захотел, они могли бы разорвать приложение в клочья с помощью скриптов, но мне было все равно. это будет их экземпляр, и все проблемы, которые они создают, исчезнут, когда они перезапустят приложение, если они не испортили файлы на HD. Я хочу предотвратить проблемы, которые возникают, когда пользователь вводит что-то глупое.
такие вещи, как IOError, SystaxErrors, InfiniteLoopErrors и т. Д.

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

также, если пользователь использует оператор import module для загрузки модуля даже из библиотеки по умолчанию, которая не используется в остальной части класса. могло ли это вызвать проблемы с зависанием приложения с помощью Py2exe, Py2app или Freeze? что, если они вызовут модальную часть стандартной библиотеки? будет ли достаточно, чтобы модальный файл находился в том же каталоге, что и замороженный исполняемый файл?

Я хотел бы получить эти ответы, не задавая новых вопросов, но сделаю это, если потребуется.


person Ryex    schedule 14.10.2010    source источник
comment
Eval практически невозможно сделать полностью безопасным imo (но это не моя основная область знаний, я могу говорить из своей задницы). Почему бы не пойти по пути разработки API с подключаемой структурой для этого, если безопасность / интеграция и функциональные возможности вызывают беспокойство?   -  person    schedule 15.10.2010
comment
Эй, по крайней мере, это не exec.   -  person nmichaels    schedule 15.10.2010
comment
По крайней мере, осознайте, что это один из тех действительно, очень редких случаев, когда gotta-catch-'em-all except: имеет смысл и применяет его. Нет необходимости сбой всего приложения, потому что пользователь, относительно новичок в python, пропустил место. +1 и приветствую, я с нетерпением жду возможности включить Python REPL в свое приложение.   -  person    schedule 15.10.2010
comment
^^ Это то, о чем я действительно беспокоюсь. Я знаю, что теперь есть способ полностью остановить того, кто пытается причинить вред. Я больше беспокоился о том, чтобы эта синтаксическая ошибка или ошибка ввода-вывода не привели к сбою программы. и предотвращение непреднамеренного изменения критически важных данных формой пользователя. в основном из того, что я вижу здесь, совет: используйте try: except :, храните важные данные вне области действия eval, предоставляйте безопасные функции для доступа и изменения вещей, которые могут сломаться.   -  person Ryex    schedule 15.10.2010


Ответы (4)


Простой ответ: не надо.

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

Тем не менее, я сделал такие вещи для веб-приложений, которые выполняют ввод данных пользователем и да, вызывают eval вот так:

eval(code, {"__builtins__":None}, {safe_functions})

где safe_functions - это словарь, содержащий {"name": func} пары функций, к которым ваши пользователи должны иметь доступ. Если есть какая-то важная структура данных, которую, как вы уверены, пользователи никогда не захотят трогать, просто извлеките ее из globals, прежде чем передавать.

Между прочим, Гвидо недавно затронул эту проблему в своем блоге. Я посмотрю, смогу ли я его найти.

Изменить: найдено.

person nmichaels    schedule 14.10.2010
comment
Простой ответ: не надо. -ХА! правда, однако при создании этого приложения я стремился 1) узнать много нового о Python 2) создать приложение, которое действительно можно использовать эффективно и эффективно. Я знаю, что полностью предотвратить нарушение пользователем чего-либо невозможно, если не разрешить ему запускать код. но, конечно, можно предотвратить сбой приложения, если код вызывает ошибку, которой они не ожидали в обстоятельствах, которых они не ожидали. или остановить выполнение своего кода, если он завис из-за того, что что-то пошло не так. - person Ryex; 15.10.2010
comment
Я имел в виду не ограничивать это. Добавление функциональности сценариев отлично подходит для опытных пользователей, но предостережение о том, что они могут что-то сломать, применимо практически повсеместно. - person nmichaels; 15.10.2010
comment
Вместо этого вы можете встроить что-то вроде PyV8 (code.google.com/p/pyv8), так что вы все равно получите полноценный язык программирования, но вам придется предоставить свои собственные глобальные переменные и добавить дополнительную зависимость. - person li.davidm; 15.10.2010

Короткий ответ: нет

Другие связанные сообщения:

Создать страховочную сетку непросто. Слишком много деталей и умных хаков:

О целях вашего дизайна:

Похоже, вы пытаетесь построить расширяемую систему, предоставляя пользователю возможность изменять множество действий и логики.

Самый простой вариант - попросить их написать сценарий, который вы сможете оценить (eval) во время выполнения программы.

Однако хороший дизайн описывает, ограничивает гибкость и предоставляет механизм сценариев с помощью различных схем проектирования, начиная от конфигурации, плагина и заканчивая возможностями создания сценариев и т. Д. API сценариев, если они четко определены, может обеспечить более значимую расширяемость. Это тоже безопаснее.

person pyfunc    schedule 14.10.2010
comment
Я не могу полностью согласиться или не согласиться с последней частью. Приложение, которое позволяет мне создавать сценарии, поможет мне быть более продуктивным (о, все эти X должны быть Y ... ну, я напишу цикл, который это исправит). Это дешевое решение для опытных пользователей. Но, конечно, настоящая конфигурация и плагины очень удобны, а также доступны большему количеству пользователей. - person ; 15.10.2010
comment
@delnan: Полностью согласен с вами. Но для большинства пользователей все же более полезно обеспечить расширяемость с помощью плагинов, API сценариев и т. Д. Работа, которую продвинутый пользователь будет делать, будет очень творческой, но чистый лист обычно не работает с большинством пользователей. - person pyfunc; 15.10.2010

Я бы посоветовал предоставить какой-то плагин API и разрешить пользователям предоставлять плагины в виде текстовых файлов. Затем вы можете импортировать их как модули в их собственное пространство имен, выявляя синтаксические ошибки в процессе, и вызывать различные функции, определенные в подключаемом модуле, снова проверяя наличие ошибок. Вы можете предоставить модуль API, который определяет функции / классы из вашей программы, к которым подключаемый модуль имеет доступ. Это дает вам свободу вносить изменения в архитектуру вашего приложения, не нарушая работу подключаемых модулей, поскольку вы можете просто адаптировать модуль API, чтобы таким же образом раскрыть функциональность.

person kindall    schedule 15.10.2010

Если у вас есть возможность переключиться на Tkinter, вы можете использовать встроенный интерпретатор tcl для обработки вашего скрипта. В этом отношении вы, вероятно, можете сделать это с помощью приложения wxpython, если не запускаете цикл событий tk; просто используйте интерпретатор tcl, не создавая никаких окон.

Поскольку интерпретатор tcl - это отдельная вещь, должно быть почти невозможно вызвать сбой интерпретатора python, если вы будете осторожны с тем, какие команды вы предоставляете tcl. Кроме того, tcl упрощает создание DSL.

Python - единственный скриптовый язык со встроенным скриптовым движком :-).

person Bryan Oakley    schedule 15.10.2010