[求教] 如何实现一个沙盒机制来执行来自字符串的 Python 代码 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Hualin

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

  •  
  •   Hualin 2013 年 7 月 17 日 3777 次点击
    这是一个创建于 4666 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #背景

    手头的项目是关于科学计算的。一个大的数据集,分别由以下几个文件组成:
    + 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 里面的输入,如何创建一个安全的执行环境?
    第 1 条附言    2013 年 7 月 18 日
    搞定了。
    之间有点小插曲,被 python 的参数传递机制给坑了。
    我在 json 的配置文件里定义了个域,之间把 numpy 的表达式写了进去作为一个字符串,然后从程序中 eval 这个字符串,eval 的另一个参数 globals 我直接讲 labelDict (字典类型)传了进去。可是程序总是执行的不对。在该函数调用的外面,有一个变量也是 labelDict 是原始。我发现一个坑爹的现象。

    在 eval(subsetString, labelDict) 后 labelDict 的类型从原来单纯的 数据字典,变成了 python 全局环境字典。anyway,后来我发现,在这个函数调用过后,labelDict 在该函数调用支出的 父函数的类型也发生了突变。
    后来我改为 eval(subsetString, labelDict.copy()) 便没事了。

    昨天看了一片文章,说 python 函数参数突变类型,今天就遇上了类似的坑,真是好险。。。
    2 条回复    1970-01-01 08:00:00 +08:00
    dndx
        1
    dndx  
       2013 年 7 月 17 日 via iPad   1
    请参考 http://docs.python.org/2/reference/simple_stmts.html#exec
    或者
    http://docs.python.org/2/library/functions.html#eval

    这两种方法都可以指定执行时使用的 globals 和 locals 。直接 pass 一个 dict 过去即可避免污染当前环境。
    dreampuf
        2
    dreampuf  
       2013 年 7 月 18 日
    @dndx 防君子可以,防小人可不能这么马虎 http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2965 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 13:02 PVG 21:02 LAX 06:02 JFK 09:02
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86