[求教] 如何实现一个沙盒机制来执行来自字符串的 Python 代码

2013-07-17 07:06:10 +08:00
 Hualin
#背景

手头的项目是关于科学计算的。一个大的数据集,分别由以下几个文件组成:
+ crdArr => N个数据的坐标;
+ labelDict => N个数据的数据属性字典,如 labelDict["some_key"] 里面存着一个长度为N的某种属性的数据,相当于一个 speadsheet,key 作为 header 的索引键;
+ disMtx => N*N 的距离矩阵。

程序需要根据 labelDict 中的属性用数学表达式从 N 个数据中得到一个子集的 subset Index。每一个 subset index 作用到原有数据集会得到一个子集,这个子集生成一个叫做 collection 的对象然后交给后面的模块。。。

过去选取子集的代码都是写死在 python 里,用 Numpy (一个科学计算的 python 库,类似 Matlab),后来为了灵活,我在外面写了一个 json 的配置文件,把要设置的参数全部放进去。so far so good。
问题是,选取子集需要一个可能互相嵌套的数学表达式,比如:
idx = (labelDict["age"] > 30 && labelDict["age"] < 40) && (labelDict["occupation"] == "teacher")

这种表达式很容易用 numpy 的语法实现。但是 json object 是一个较为 flat 的结构,我没法在里面实现数学表达式的复杂逻辑和互相嵌套。目前在 json 文件中我只能把选取逻辑做成一个 list,然后一条一条的做逻辑运算,但很显然这种平坦结构的表达无法实现嵌套,可是如果用 json 来写一个数学表达式显然不合适。

还有一个原因,就是这个项目需要用户在程序执行的时候动态选取一个子集,这就是没法把选取子集的代码写死在 python 里的原因,同样,json 的配置文件也只是一个暂时的策略。我需要一个 GUI 来让用户输入可能的数学表达式来提取他子集需要的数据子集。所以我没法用 GUI 的控件来让用户设定子集选取表达式,而是想叫用户直接在文本框输入这种表达式。问题来了!!

# 问题
我觉得我完全没必要自己重新发明一个 正则表达式来 parse 用户输入的表达式,或者导入什么 Excel 的模块来完成这个任务。因为 Numpy 的语法本身就很清晰易懂。

所以我决定用 Python 自己的 eval 或者 complie 来提取用户在文本框输入的 Numpy 表达式。

可是,,,

首先这种方式很不安全,用户可以输入任何 python 代码,虽然我的程序不是网络程序,只是个科学计算软件,但是总觉得不放心。
理想方式是创建一个沙河机制,用户在文本框输入的 numpy 表达式在一个沙盒中 eval,有限的 namespace,有限的权限。这样基本上限制用户只能输入应该输入的。


# 实验
我刚刚做了个实验,写了一个 py 文件:
arr = array([1,2,3,4])
ss = sum(arr)

用 python 直接执行这个文件是不行的,因为 array() 函数不在命名空间中。
然后我打开 ipython
$ ipython
$ from numpy import array
$ excufile("the_file_I_mentioned_above.py")
$ print arr
$ print ss
以上可以执行,说明 excufile 是不管上下文的,需要我提前配置好上下文环境。

可问题是,我怎样限制用户在 eval 里面的输入,如何创建一个安全的执行环境?
3346 次点击
所在节点    Python
2 条回复
dndx
2013-07-17 09:10:27 +08:00
请参考 http://docs.python.org/2/reference/simple_stmts.html#exec
或者
http://docs.python.org/2/library/functions.html#eval

这两种方法都可以指定执行时使用的 globals 和 locals 。直接 pass 一个 dict 过去即可避免污染当前环境。
dreampuf
2013-07-18 01:34:11 +08:00
@dndx 防君子可以,防小人可不能这么马虎 http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/76034

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX