Python - 创建“脚本”系统
我正在制作一个 wxpython 应用程序,我将使用各种冻结实用程序进行编译,以创建适用于多个平台的可执行文件。
该程序将是
此应用程序中基于图块的游戏引擎的地图编辑器,我想提供一个脚本系统,以便高级用户可以修改程序的行为,例如修改项目数据、将项目导出为不同的格式等。
我希望系统像这样工作。
用户将他们想要运行的 python 脚本放入样式文本框中,然后按下按钮来执行脚本。
到目前为止我对此很满意,这都是非常简单的事情。 从文本框中获取脚本作为字符串使用内置函数compile()将其编译为cod对象然后使用exec语句执行脚本
script = textbox.text #bla bla store the string
code = compile(script, "script", "exec") #make the code object
eval(code, globals())
事情是,我想确保此功能不会导致任何错误或错误
说明脚本中是否有 import 语句。考虑到代码是用 py2exe 或 py2app 等编译的,这会导致任何问题吗?
如何确保用户不能破坏程序的关键部分,例如修改 GUI 的部分,同时仍然允许他们修改项目数据(数据保存在其自己模块的全局属性中)?我认为这意味着修改传递给 eval 函数的全局字典。
如何确保此 eval 不会导致程序因长循环或无限循环而挂起? 如何确保用户代码中引发的错误不会导致整个应用程序崩溃?
基本上,如何避免允许用户运行自己的代码时可能出现的所有这些问题?
编辑:关于给出的答案
我觉得到目前为止没有任何答案真正回答了我的问题 是的,他们已经得到了部分答复,但尚未完全答复。我很清楚完全阻止不安全代码是不可能的。人们太聪明了,一个人(甚至一群人)不可能想出所有绕过安全系统并阻止它们的方法。
事实上我并不关心他们是否这样做。我更担心有人无意中破坏了他们不知道的东西。如果有人真的愿意,他们可以使用脚本功能将应用程序撕成碎片,但我不在乎。这将是他们的实例,当他们重新启动应用程序时,他们造成的所有问题都会消失,除非他们弄乱了硬盘上的文件。 我想防止当用户做了一些愚蠢的事情时出现的问题。
诸如 IOError、SystaxErrors、InfiniteLoopErrors 等。
现在关于范围的部分已经得到解答。我现在了解如何定义可以从 eval
函数访问哪些函数和全局变量 但是有没有办法确保在代码执行时间过长时可以停止执行?
也许是一个绿色线程系统? (绿色是因为 eval 会让用户担心线程安全)
还有如果用户使用 import module
语句从默认库中加载模块t 在班级的其余部分中使用。这是否会导致应用程序被 Py2exe、Py2app 或 Freeze 冻结时出现问题?如果他们调用标准库之外的模态怎么办?模式与冻结的可执行文件位于同一目录中就足够了吗?
我想在不提出新问题的情况下得到这些答案,但如果必须的话我会的。
I'm making a wxpython app that I will compile with the various freezing utility out there to create an executable for multiple platforms.
the program will be a map editer for a tile-based game engine
in this app I want to provide a scripting system so that advanced users can modify the behavior of the program such as modifying project data, exporting the project to a different format ect.
I want the system to work like so.
the user will place the python script they wish to run into a styled textbox and then press a button to execute the script.
I'm good with this so far thats all really simple stuff.
obtain the script from the text-box as a string compile it to a cod object with the inbuilt function compile() then execute the script with an exec statment
script = textbox.text #bla bla store the string
code = compile(script, "script", "exec") #make the code object
eval(code, globals())
the thing is, I want to make sure that this feature can't cause any errors or bugs
say if there is an import statement in the script. will this cause any problems taking into account that the code has been compiled with something like py2exe or py2app?
how do I make sure that the user can't break critical part of the program like modifying part of the GUI while still allowing them to modify the project data (the data is held in global properties in it's own module)? I think that this would mean modifying the globals dict that is passed to the eval function.
how to I make sure that this eval can't cause the program to hang due to a long or infinite loop?
how do I make sure that an error raised inside the user's code can't crash the whole app?
basically, how to I avoid all those problems that can arise when allowing the user to run their own code?
EDIT: Concerning the answers given
I don't feel like any of the answers so far have really answered my questions
yes they have been in part answered but not completely. I'm well aware the it is impossible to completely stop unsafe code. people are just too clever for one man (or even a teem) to think of all the ways to get around a security system and prevent them.
in fact I don't really care if they do. I'm more worried about some one unintentional breaking something they didn't know about. if some one really wanted to they could tear the app to shreds with the scripting functionality, but I couldn't care less. it will be their instance and all the problem they create will be gone when they restart the app unless they have messed with files on the HD.
I want to prevent the problems that arise when the user dose something stupid.
things like IOError's, SystaxErrors, InfiniteLoopErrors ect.
now the part about scope has been answered. I now understand how to define what functions and globals can be accessed from the eval
function
but is there a way to make sure that the execution of their code can be stopped if it is taking too long?
a green thread system perhaps? (green because it would be eval to make users worry about thread safety)
also if a users uses an import module
statement to load a module from even the default library that isn't used in the rest of the class. could this cause problems with the app being frozen by Py2exe, Py2app, or Freeze? what if they call a modal out side of the standard library? would it be enough that the modal is present in the same directory as the frozen executable?
I would like to get these answers with out creating a new question but I will if I must.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
简单回答:不。
您可以禁止某些关键字(
import
)和操作,以及对某些数据结构的访问,但最终您会授予高级用户相当大的权力。由于这是针对在用户计算机上运行的富客户端的,因此恶意用户可以崩溃甚至丢弃整个应用程序(如果他们真的愿意的话)。但这是他们崩溃的例子。很好地记录下来并告诉人们不要碰什么。也就是说,我已经为执行用户输入的网络应用程序做了这种事情,是的,像这样调用 eval:
其中 safe_functions 是一个包含
{"name": func}
类型函数对的字典您希望您的用户能够访问。如果您肯定有一些基本的数据结构,您的用户永远不想去查看,只需在将它们传入之前将其从全局
中弹出即可。顺便说一句,Guido 解决了这个问题不久前在他的博客上发布了一个问题。我看看能不能找到它。
编辑: 找到。
Easy answer: don't.
You can forbid certain keywords (
import
) and operations, and accesses to certain data structures, but ultimately you're giving your power users quite a bit of power. Since this is for a rich client that runs on the user's machine, a malicious user can crash or even trash the whole app if they really feel like it. But it's their instance to crash. Document it well and tell people what not to touch.That said, I've done this sort of thing for web apps that execute user input and yes, call eval like this:
where safe_functions is a dictionary containing
{"name": func}
type pairs of functions you want your users to be able to access. If there's some essential data structure that you're positive your users will never want to poke at, just pop it out ofglobals
before passing them in.Incidentally, Guido addressed this issue on his blog a while ago. I'll see if I can find it.
Edit: found.
简短回答:否
其他相关帖子:
建立安全网并不容易。周围有太多聪明的黑客:
您似乎正在尝试通过提供用户修改大量行为和逻辑来构建可扩展的系统。
最简单的选择是要求他们编写一个脚本,您可以在程序运行期间对其进行评估(eval)。
然而,一个好的设计通过从配置、插件到脚本功能等各种设计方案来描述、确定灵活性并提供脚本机制。如果定义良好的脚本 API 可以提供更有意义的可扩展性。它也更安全。
Short Answer: No
Other related posts:
It is not easy to create a safety net. The details too many and clever hacks are around:
It seems you are trying to build an extensible system by providing user to modify a lot of behavior and logic.
Easiest option is to ask them to write a script which you can evaluate (eval) during the program run.
How ever, a good design describes , scopes the flexibility and provides scripting mechanism through various design schemes ranging from configuration, plugin to scripting capabilities etc. The scripting apis if well defined can provide more meaningful extensibility. It is safer too.
我建议提供某种插件API并允许用户以文本文件的形式提供插件。然后,您可以将它们作为模块导入到它们自己的命名空间中,捕获过程中的语法错误,并调用插件模块中定义的各种函数,再次检查错误。您可以提供一个 API 模块,该模块定义插件模块可以访问的程序中的函数/类。这使您可以自由地更改应用程序的架构,而无需破坏插件,因为您只需调整 API 模块即可以相同的方式公开功能。
I'd suggest providing some kind of plug-in API and allowing users to provide plug-ins in the form of text files. You can then import them as modules into their own namespace, catching syntax errors in the process, and call the various functions defined in the plug-in module, again checking for errors. You can provide an API module that defines the functions/classes from your program that the plug-in module has access to. That gives you the freedom to make changes to your application's architecture without breaking plug-ins, since you can just adapt the API module to expose the functionality in the same way.
如果您可以选择切换到 Tkinter,则可以使用捆绑的 tcl 解释器来处理您的脚本。就此而言,如果您不启动 tk 事件循环,您可能可以使用 wxpython 应用程序来做到这一点;只需使用 tcl 解释器而不创建任何窗口。
由于 tcl 解释器是一个单独的东西,如果您仔细考虑向 tcl 公开的命令,那么几乎不可能使 python 解释器崩溃。另外,tcl 使创建 DSL 变得非常容易。
Python - 唯一具有内置脚本引擎的脚本语言:-)。
If you have the option to switch to Tkinter you can use the bundled tcl interpreter to process your script. For that matter you can probably do that with a wxpython app if you don't start the tk event loop; just use the tcl interpreter without creating any windows.
Since the tcl interpreter is a separate thing it should be nearly impossible to crash the python interpreter if you are careful about what commands you expose to tcl. Plus, tcl makes creating DSLs very easy.
Python - the only scripting language with a built-in scripting engine :-).