eval(expression[, globals[, locals]])

eval()函数执行一个python表达式字符串并返回表达式执行后的结果:

>>> x = 1
>>> eval('x + 1')
2

expression参数为一个表达式字符串,globalslocals为可选的参数,globals必须是一个字典对象,locals可为任意映射对象,分别用作代码执行的全局和局部命名空间。

globalslocals参数缺失的时候,表达式会使用当前环境的全局和局部命名空间值:

>>> x = 1
>>> g = {'x' : 2}
>>> eval('x + 1', g)
3
>>> eval('x + 1')
2

eval()函数在数据类型转换中很有用,可以将字符串转换成字典、列表等:

>>> exp = '[1,2,3,4]'
>>> eval(exp)
[1, 2, 3, 4]
>>> exp = '{"a" : 1}'
>>> eval(exp)
{'a': 1}

eval()也可以使用模块:

>>> import os
>>> eval('os.getcwd()')
'/home/user'

当然,eval不能直接对模块进行操作,如果非要使用eval进行import:

>>> eval('__import__("os").getcwd()')
'/home/user'

这一般用于根据客户需求动态的调用不同的模块。

其它的用做计算器啥的也不在话下,不过eval函数也不能滥用,比如要获取用户的输入并求值eval(raw_input()),

这种情况下,用户输入open(__file__).read()可直接把原文件读出来了。

要安全的使用eval()函数,可以使用globals和locals两个参数来设置白名单,当参数缺失的时候,表达式会使用当前环境的全局和局部命名空间值,即globals()和locals()中包含的模块和函数:

>>> import os
>>> 'os' in globals()
True
>>> eval('os.getcwd()')
'/home/user'

将globals和locals两个参数设置为空:

>>> import os
>>> eval('os.getcwd()', {}, {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'os' is not defined

但使用内置函数却可以绕过白名单:

>>> eval('abs(10)', {}, {})
10
>>> eval('__import__("os").getcwd()', {}, {})
'/home/user'

可以看下globals():

>>> globals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}

__builtins__设置着python的内置函数,下面的写法是一样的:

>>> abs(10)
10
>>> __builtins__.abs(10)
10

将__builtins__设置为空则可避免内置函数的滥用:

>>> eval('abs(10)', {'__builtins__' : None}, {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'abs' is not defined 

看情况这下是安全了,但是还是可以绕过的:

>>> ().__class__.__bases__[0].__subclasses__()
[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'sys.getwindowsversion'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'nt.stat_result'>, <type 'nt.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <type 'operator.itemgetter'>, <type 'operator.attrgetter'>, <type 'operator.methodcaller'>, <type 'functools.partial'>, <type 'MultibyteCodec'>, <type 'MultibyteIncrementalEncoder'>, <type 'MultibyteIncrementalDecoder'>, <type 'MultibyteStreamReader'>, <type 'MultibyteStreamWriter'>, <type 'time.struct_time'>, <type '_ssl._SSLContext'>, <type '_ssl._SSLSocket'>, <type 'cStringIO.StringO'>, <type 'cStringIO.StringI'>, <class 'socket._closedsocket'>, <type '_socket.socket'>, <type 'method_descriptor'>, <class 'socket._socketobject'>, <class 'socket._fileobject'>, <type '_thread._localdummy'>, <type 'thread._local'>, <type 'thread.lock'>, <type 'collections.deque'>, <type 'deque_iterator'>, <type 'deque_reverse_iterator'>, <type 'itertools.combinations'>, <type 'itertools.combinations_with_replacement'>, <type 'itertools.cycle'>, <type 'itertools.dropwhile'>, <type 'itertools.takewhile'>, <type 'itertools.islice'>, <type 'itertools.starmap'>, <type 'itertools.imap'>, <type 'itertools.chain'>, <type 'itertools.compress'>, <type 'itertools.ifilter'>, <type 'itertools.ifilterfalse'>, <type 'itertools.count'>, <type 'itertools.izip'>, <type 'itertools.izip_longest'>, <type 'itertools.permutations'>, <type 'itertools.product'>, <type 'itertools.repeat'>, <type 'itertools.groupby'>, <type 'itertools.tee_dataobject'>, <type 'itertools.tee'>, <type 'itertools._grouper'>, <class 'threading._Verbose'>, <class 'string.Template'>, <class 'string.Formatter'>, <type 'CArgObject'>, <type '_ctypes.CThunkObject'>, <type '_ctypes._CData'>, <type '_ctypes.CField'>, <type '_ctypes.DictRemover'>, <type 'Struct'>, <class 'ctypes.CDLL'>, <class 'ctypes.LibraryLoader'>, <type 'cPickle.Unpickler'>, <type 'cPickle.Pickler'>, <class 'idlelib.rpc.SocketIO'>, <class 'idlelib.rpc.RemoteObject'>, <class 'idlelib.rpc.RemoteProxy'>, <class 'idlelib.rpc.RPCProxy'>, <class 'idlelib.rpc.MethodProxy'>, <type '_io._IOBase'>, <type '_io.IncrementalNewlineDecoder'>, <class 'subprocess.Popen'>, <class 'webbrowser.BaseBrowser'>, <class 'idlelib.tabbedpages.Page'>, <class 'idlelib.EditorWindow.HelpDialog'>, <type '_hashlib.HASH'>, <type '_random.Random'>, <class 'idlelib.EditorWindow.EditorWindow'>, <class 'idlelib.EditorWindow.IndentSearcher'>, <class 'idlelib.run.Executive'>]

通过tuple的class找到它的基类,也就是object,然后再找到object的各种子类,从中可以看到很多模块。

使用Quitter退出解释器:

>>> eval("[x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__== 'Quitter'][0](0)()", {'__builtins__':None})
user:~$

configobj,urllib,urllib2,setuptools等模块中都有os模块的内置:

>>> import configobj
>>> 'os' in configobj.__dict__
True
>>> import urllib2
>>> 'os' in urllib2.__dict__
True
>>> import setuptools
>>> 'os' in setuptools.__dict__
True

使用zipimport通过egg文件导入这些模块就可以使用os模块了:

eval("[x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == 'zipimporter'][0]('/path/to/configobj-5.0.5-py2.7.egg').load_module('configobj').os.getcwd()", {'__builtins__':None})

以上可以看出,eval()函数的漏洞还是很多的,如果只是用来做类型转换,可以使用ast.literal_eval 代替eval:

>>> import ast
>>> ast.literal_eval('[1, 2, 3]')
[1, 2, 3]
>>> ast.literal_eval('abs(10)') Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
ast.literal_eval('abs(10)')
File "C:\Python27\lib\ast.py", line 80, in literal_eval
return _convert(node_or_string)
File "C:\Python27\lib\ast.py", line 79, in _convert
raise ValueError('malformed string')
ValueError: malformed string
>>> eval('abs(10)')
10

 exec(str [, globals[, locals]])

 execfile(filename [, globals[, locals]])

类似的,exec函数执行一个包含python代码的字符串,execfile则执行一个文件,后两个参数与eval类似。

>>> a = [1, 2, 3, 4]
>>> exec('for i in a: print i')
activate_this = '/path/to/env/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

给eval或者exec函数传递字符串时,解析器首先会把字符串编译成字节码,为避免消耗资源,可以使用compile函数将字符串预编译:

compile(str, filename, kind)

str是要预编译的字符串,filename为字符串所在的文件,kind参数为single时代表一条语句,exec代表一组语句,eval代表一个表达式

>>> s = 'for i in [1, 2, 3]: print i'
>>> c = compile(s, '', 'exec')
>>> exec(c)
1
2
3
>>> s2 = '1+1'
>>> c2 = compile(s2, '', 'eval')
>>> eval(c2)
2

eval执行exec类型的预编译字节码时,会返回None:

>>> s2 = '1+1'
>>> c2 = compile(s2, '', 'exec')
>>> print eval(c2)
None

以前看到过一个案例,使用eval转换不规则的json数据:

>>> blog = "{url : 'www.example.com'}"

上面url缺少引号,使用eval和json.loads()均会报错。

>>> eval(blog)
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
eval(blog)
File "<string>", line 1, in <module>
NameError: name 'url' is not defined

使用eval时,eval会将url视为变量名并试图在globals和locals中寻找url的值,添加一下globals参数:

>>> eval(blog, {'url' : 'url'})
{'url': 'www.example.com'}

所以,现在要做的是就是建立一个类dict的映射对象,其中value的值需要与key值相同,可以使用type函数来建立:

>>> ValueFromKey = type('ValueFromKey', (dict,), dict(__getitem__ = lambda self,k : k))
>>> eval(blog, ValueFromKey())
{'url': 'www.example.com'}

在新建的type对象基类元祖中包含下dict,然后在对象的dict中定义一下__getitem__方法,使value值与key值一致即可。

eval()、exec()与execfile()的更多相关文章

  1. python中eval, exec, execfile,和compile [转载]

    eval(str [,globals [,locals ]])函数将字符串str当成有效Python表达式来求值,并返回计算结果. 同样地, exec语句将字符串str当成有效Python代码来执行. ...

  2. python中eval, exec, execfile,和compile

    eval(str [,globals [,locals ]])函数将字符串str当成有效Python表达式来求值,并返回计算结果. 同样地, exec语句将字符串str当成有效Python代码来执行. ...

  3. 执行字符串或注释代码段的方法(eval、exec、execfile)

    eval:计算字符串中的表达式exec:执行字符串中的语句execfile:用来执行一个文件 需注意的是,exec是一个语句,而eval()和execfile()则是内建built-in函数. 1 2 ...

  4. bash,bg,bind,break,builtin,caller,compgen, complete,compopt,continue,declare,dirs,disown,enable,eval,exec,expo

    bash,bg,bind,break,builtin,caller,compgen, complete,compopt,continue,declare,dirs,disown,enable,eval ...

  5. eval & exec(绕过长度限制思路学习)

    eval & exec知识点记录--原文章phithon,只是记录一下我自己的学习过程. 1.eval & exec if(strlen($param)<17 && ...

  6. python-内置函数-compile,eval,exec

    #将字符串,编译成python代码 compile()#执行,有返回值,执行表达式并获取结果 eval()#执行python代码,无返回值,接收:代码或者字符串 exec() s = "pr ...

  7. Python 执行字符串表达式函数(eval exec execfile)

    eval:计算字符串中的表达式 exec:执行字符串中的语句 execfile:用来执行一个文件 在python 2中exec是语句,在python3中exec变为函数,后面要跟括号.在python3 ...

  8. eval、exec、execfile

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #http://blog.csdn.net/azhao_dn/article/details/6921654 ...

  9. Python中的eval(),exec()以及其相关函数

    1. eval函数 函数的作用: 计算指定表达式的值.也就是说它要执行的Python代码只能是单个运算表达式(注意eval不支持任意形式的赋值操作),而不能是复杂的代码逻辑,这一点和lambda表达式 ...

随机推荐

  1. oracle 常用(二)

    多表查询: 1.等值连接查询: select a.aa,a.bb,b.qq from XX  a ,   CC  b   where a.aa= b.ee 2.不等值连接: select  *  fr ...

  2. Spark Streaming 002 统计单词的例子

    1.准备 事先在hdfs上创建两个目录: 保存上传数据的目录:hdfs://alamps:9000/library/SparkStreaming/data checkpoint的目录:hdfs://a ...

  3. SpringBoot的json序列化及时间序列化处理

    使用场景:前台的多种时间格式存入后台,后台返回同时的时间格式到前台. 1 在config目录下配置jscksonConfig.java package com.test.domi.config; im ...

  4. linux文件目录管理命令

    1.touch命令 touch命令用于创建空白文件或设置文件的时间,格式为“touch [选项] [文件]”. touch test命令可以创建出一个名为test的空白文本文件  touch命令的参数 ...

  5. 《大话设计模式》c++实现 建造者模式

    一.UML图 关键词:Subject维护一个Observer列表,Subject执行Notify()时就执行列表中的每个Observer的Update(). 二.概念 观察者模式:定义了一种一对多的依 ...

  6. repr()函数

    http://www.cnblogs.com/itdyb/p/5046415.html

  7. Python 1.安装

    Python是一种开源语言,有很多第三方库. 1. Python3 及相关组件下载及安装 a. Python3下载:https://www.python.org/downloads/->点击以下 ...

  8. Java集合-----List详解

    List中的元素是有序排列的而且可重复 1.LinkedList LinkedList是非线程安全的,底层是基于双向链表实现的       LinkedList常用方法:     toArray()  ...

  9. 基于word2vec训练词向量(二)

    转自:http://www.tensorflownews.com/2018/04/19/word2vec2/ 一.基于Hierarchical Softmax的word2vec模型的缺点 上篇说了Hi ...

  10. Ford VCM II Ford VCM2 Diagnostic Tool with Ford IDS v108 Installed On Laptop Ready to Use

    HOW to VCM2 Ford VCM II with Ford IDS v108 Work Well? VCM2 Ford VCM2 Ford diagnostic tool hot sale i ...