eval ("1+1==2")
True
eval("'A'+ 'B'")
'AB'
eval("1+2")
3
Python中 eval()
函数将宇符串 str
当成有效的表达式来求值并返回计算结果。
其函数声明如下:
eval(expression(,globals[r,locals]])
import sys
from math import *
def ExpCalcBot(string):
try:
print( 'Your answer is',eval (user_func))# 计算输入的值
except NameError:
print ("The expression you enter is not valid")
print ('Hi/1 am ExpCalcBot. please input your experssion or enter e to end')
inputstr =''
while 1:
print ('enter A number or operation. Enter c to complete.:' )
inputstr = input()
if inputstr ==str('e') :#遇到靖入为e的时候退出
sys.exit ()
elif repr(inputstr)!= repr(''):
ExpCalcBot(inputstr)
inputstr = ''
Hi/1 am ExpCalcBot. please input your experssion or enter e to end enter A number or operation. Enter c to complete.:
An exception has occurred, use %tb to see the full traceback.
SystemExit
上面这段代码的主要功能是:根据用户的输入,计算Python表达式的值。
它有什么问题呢?如果用户都是素质良好,没有不良目的的话,那么这段程序也许可以满足基本需求。
比如,输入 1+sin(20)
会输出结果 1.91294525073
。
但如果它是一个Web页面的后台调用(当然,需要做一定的修改),由于网络环境下运行它的用户并非都是可信任的,
问题就出现了,因为 eval()
可以将任何字符串当做表达式求值,这也就意味着有空子可钻。
于是顿时,有人的“坏心眼”来了,他输入了如下字符串,可悲的事情发生了,
当前目录下的所有文件都被删除了,包括 test.py
,而这一切没有任何提示,悄无声息。
_import_("os").system("dir") !!!不要轻易在你的计算机上尝试
Your answer is 0
试想,在网络环境下这是不是很危险?
那是因为没有在 globals
参数中禁止全局命名空间的访问。
试验一下:将函数 ExpCalcBot
修改一 下,
其中 math_flun_list
限定为几个常用的数学函数。修改后的函数如下:
def ExpCalcBot(string):
try:
math_fun_list = ['acos', 'asin', 'atan', 'cos', 'e', 'log', 'log10','pi', 'pow', 'sin', 'sqrt', 'tan']
math_fun_diet = dict ([(k, globals().get (k) ) for k in math_fun_list]) #>成$以访问的函數的字與
print (' Your answer is', eval (string, {"_builtins_": None} ,math_fun_dict) )
except NameError:
print ("The expression you enter is not valid")
再次运行程序(请读者自行试验)会惊喜地发现上面的命令被看着无效表达式。 很好,安全问题不再是个问题! 但仔细想想真是这样的吗?试试输入以下字符:
[c for c in ().__class__.__bases__[0].__subclasses__() if c.__name__ =='Quitter'[0](0)()
# ().__class__._bases__[0]._subclasses_()
用来显示 object
类的所有子类。类 Quitter
与 "quit"
功能綁定,因此上面的输入会直接导致程序退出。
注:可以在Python的安装目录下的 Lib\site.py
中找到其类的定义。
也可以自行在 Python 解释器中输入 print().__ctass__.__bases__[0].__subclasses__()
看看输出结果是什么。
因此对于有经验的侵入者来说,他可能会有一系列强大的手段,
使得 eval
可以解释和调用这些方法,从而带来更大的破坏。
此外,evai()
函数也给程序的调试带来一定困难,要查看 eval()
里面表达式具体的执行过程很难。
因此在实际应用过程中如果使用对象不是信任源,
应该尽量避免使用 eval
,在需要使用eval的地方可用安全性更好的 ast.literal_eval
替代。
literal_eval
函数具体详情可以参考文档 http://docs.python.org/2/library/ast.html#ast.literaLeval
上面的例子请使用 literal_eval
自行试验。