您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > Python

被企业禁用的,那些python中的内置强大函数

时间:2023-01-05 14:23:34  来源:  作者:互联共商

eval()函数是Python/ target=_blank class=infotextkey>Python的内置函数,功能非常强大,但是存在不小的安全隐患。有些企业或项目出于安全考虑,禁止使用eval()函数,会在一些安全相关的扫描校验中进行识别和拦截,杜绝使用。

究竟eval()函数强大在哪?又有什么安全隐患?本文将逐一进行总结分析。


 

eval()函数介绍

eval()函数语法:

 

eval(expression[, globals[, locals]]) expression: 字符串表达式。globals: 可选参数,全局变量,如果设置,则必须是一个字典对象。locals: 可选参数,局部变量,如果设置,则可以是任何映射(mApping)对象。如果只设置了globals,locals默认与globals一样。

 

eval()函数的作用是将字符串当成有效的表达式来求值并返回计算的结果。相当于去掉字符串首尾的引号,并执行去掉引号后的语句,返回执行的结果。

主要效果体现为:

 

  • 执行一个字符串表达式,并返回表达式的值。
  • 将字符串转成对应格式的数据对象(如int、list、tuple或dict)。

 

eval()函数的强大功能

1.执行字符串表达式并返回结果。

# 计算表达式 s = eval("5 + 7") print('s: ', s) s1 = eval('[i for i in range(10)]') print('s1: ', s1) 1234512345

Output:

s: 12 s1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 1212

eval()可以对字符串中的数字加法进行计算,返回计算结果。也可以直接执行字符串中的列表推导式这类表达式,返回执行的结果。

2.执行表达式时支持将变量传到字符串中。

# 传入变量 x = 111 s2 = eval("123 + x") print('s2: ', s2) # 设置globals y = 2222 s3 = eval("1234 + y", {"y": 1111}) print('s3: ', s3) # 设置globals, locals z = 22222 s4 = eval("12345 + z", {"z": 11111}, {"z": 33333}) print('s4: ', s4) 123456789101112123456789101112

Output:

s2: 234 s3: 2345 s4: 45678 123123

在eval()中执行表达式还支持传参,可以在当前 .py 代码环境中定义变量,也可以通过eval()函数的globals参数和locals参数传值。优先级locals高于globals,globals高于当前 .py代码环境的变量。

3.返回对应类型的数据。

# 将引号中的内容还原成对应类型的数据 sta = '12345' print(type(eval(sta)), eval(sta)) stb = '[1, 2, 3, 4, 5, 6, 7]' print(type(eval(stb)), eval(stb)) stc = '(2, 4, 6, 8, 10)' print(type(eval(stc)), eval(stc)) std = '{"beijing": 1, "shanghAI": 2, "guangzhou": 3, "shenzhen": 4}' print(type(eval(std)), eval(std)) 123456789123456789

Output:

12345 [1, 2, 3, 4, 5, 6, 7] (2, 4, 6, 8, 10) {'beijing': 1, 'shanghai': 2, 'guangzhou': 3, 'shenzhen': 4} 12341234

eval()函数直接返回字符串内容对应的数据类型,作用相当于将字符串首尾的引号去掉,如果不用eval(),自己转换数据类型,需要好几个步骤。


 

eval()函数经常和input()函数配合使用,直接将用户输入的字符串转换成对应类型的数据。

eval()函数也经常用于从配置文件中读取内容,读取内容的同时直接转换成对应类型。

eval()函数的安全隐患

eval()函数功能非常强大,但同时也存在不小的安全隐患,原因正是eval()可以将字符串转成表达式执行。

# 调用库执行系统命令 import os eval("os.system('whoami')") eval("os.system('echo 123')") 1234512345

Output:

desktop-xxxxxx 123 1212

如果在执行eval()函数的运行环境中导入了os模块,恶意用户可以通过eval()函数调用os模块中的系统命令函数system(),执行一系列的系统命令来达到他的目的。

如os.system(‘whoami’)可以查看当前系统的登录用户、os.system(‘dir’)可以查看当前目录下的所有文件。假如执行的是查看源码或删除数据等的命令,将会产生严重的后果。

针对这种隐患,有没有办法限制用户执行系统命令呢?

Import os print('os' in globals()) eval("os.system('whoami')") print("*"*30) # 将globals参数设置成空 eval("os.system('whoami')", {}, {}) eval("os.system('whoami')", {}) 1234567812345678

Output:

True desktop-xxxxxx ****************************** Traceback (most recent call last): File "C:/Users/xxx/Desktop/eval_demo.py", line 49, in eval("os.system('whoami')", {}, {}) File "", line 1, in NameError: name 'os' is not defined 1234567812345678

上面的代码运行环境中导入了os库,eval()中可以正常调用。假如将eval()中的globals和locals参数设置成空,eval()中就找不到os库了,执行代码报错。

eval()函数中变量加载的优先级顺序为:局部变量locals > 全局变量globals > 当前 .py环境中的变量。

这里需要注意,如果未设置locals或locals为空,则locals与globals一样。假如locals中不存在值,会再到globals中寻找值。因此,要设置locals和globals中都没有os库,才能避免用户调用。(实际应用时并不一定都是将locals和globals设置为空,设置为空只是一种示例)。

通过对locals和globals的限制,避免了用户调用当前运行环境中导入的os库。但是,限制用户使用已导入的库,用户可以自己导入库并使用。

# 导入os库并执行系统命令 eval("__import__('os').system('whoami')") eval("__import__('os').system('echo 123')") # 增加globals和locals的限制 eval("__import__('os').system('whoami')", {}) eval("__import__('os').system('echo 123')", {}, {}) 123456123456

Output:

desktop-xxxxxx 123 desktop-xxxxxx 123 12341234

如果恶意用户发现当前的运行环境中没有导入os,或者导入的os库被限制使用,调用os.system()报错。恶意用户会尝试自己导包,用__import__(‘os’)可以在eval()函数中导入os库,同时执行一系列的系统命令来达到他的目的。

这种方法是在每次执行时都导包,并立即链式执行系统命令,在globals和locals中去掉os并不能起到限制。而且,os库是python中的标准库,只要有python就一定有os库,用户必然能导入成功。

那针对这种隐患,有没有办法不让用户导包呢?

# 在globals中将__builtins__设置为None eval("__import__('os').system('whoami')", {"__builtins__": None}) 1212

Output:

Traceback (most recent call last): File "C:/Users/xxx/Desktop/eval_demo.py", line 62, in eval("__import__('os').system('whoami')", {"__builtins__": None}) File "", line 1, in TypeError: 'N.NEType' object is not subscriptable 1234512345

用户自己在eval()函数中导包,是使用__import__()函数实现的。__import__()函数是python的内建函数,是用于动态导库的函数。

print(dir(__builtins__)) 11

Output:

['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'bytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'windowsError', 'ZeroDivisionError', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip'] 11

在python中,内建函数都在__builtins__模块中,在启动python时,python解释器就直接导入了__builtins__模块中的函数。__import__()函数就是__builtins__模块中的一员,也就是说,python解释器默认导入了__import__()函数,用户可以直接调用。

上面的代码在globals参数中将__builtins__设置成None,eval()函数就获取不到__import__()函数了,无法自己导包,执行代码报错。

但是,限制用户导包,恶意用户还可以通过其他途径获取到os库。

s = '[x for x in ().__class__.__bases__[0].__subclasses__() if x.__name__ == "zipimporter"][0]("C:/Users/xxx/Lib/site-packages/setuptools-28.8.0-py3.6.egg").load_module("setuptools").os.system("whoami")' eval(s, {"__builtins__": None}) 1212

Output:

desktop-xxxxxx 11

上面这种方式也可以成功执行系统命令。代码中利用__class__和__subclasses__动态加载了基类object的所有子类(可以执行下面这行代码查看当前环境中基类都有哪些子类),然后找到了zipimporter,用zipimporter动态加载setuptools库的 .egg包,再链式调用load_module()成功导入setuptools库,从而成功调用os库执行系统命令。


 

print([x.__name__ for x in ().__class__.__bases__[0].__subclasses__()]) 11

在python中,有一些库中内置了os库,导入这些库后就能调用os库,其中就包含setuptools,此外还有configobj、urllib、urllib2等。

当然,执行上面的代码需要有对应的.egg包,如果你也想演示看效果,你可以先在自己的电脑磁盘中全局搜一下,找不到再到网络下载。

以上是eval()函数的一些安全隐患,可谓是防不胜防,在写代码时无形中就需要和恶意用户进行很多回合的思维对抗,假如有哪个细节稍微考虑不周,就会留下很大的隐患。而且,关于eval(),恶意用户还有很多可以利用的方法,如删数据、暴力占满服务器的CPU资源等。

既然用了就防不胜防,那只有不用才不会留下隐患,所以,在一些企业和项目中就禁用了eval()函数。

(当然,python中也有替代方案,那就是ast.literal_eval()函数,ast.literal_eval()函数会判断字符串内容去掉首尾的引号后是不是合法的python类型,如果不是就报错,因此ast.literal_eval()函数也只能进行类型转换。)



Tags:python   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
一篇文章教会你使用Python中三种简单的函数
所谓函数,就是指:把某些特定功能的代码组成为一个整体,这个整体就叫做函数。一、函数简介所谓函数,就是指:把某些特定功能的代码组成为一个整体,这个整体就叫做函数。二、函数定义...【详细内容】
2024-04-11  Search: python  点击:(5)  评论:(0)  加入收藏
一篇文章带你了解Python的分布式进程接口
在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。一、前言在Thread和Process中,应当优...【详细内容】
2024-04-11  Search: python  点击:(2)  评论:(0)  加入收藏
Python 可视化:Plotly 库使用基础
当使用 Plotly 进行数据可视化时,我们可以通过以下示例展示多种绘图方法,每个示例都会有详细的注释和说明。1.创建折线图import plotly.graph_objects as go# 示例1: 创建简单...【详细内容】
2024-04-01  Search: python  点击:(8)  评论:(0)  加入收藏
Python 办公神器:教你使用 Python 批量制作 PPT
介绍本文将介绍如何使用openpyxl和pptx库来批量制作PPT奖状。本文假设你已经安装了python和这两个库。本文的场景是:一名基层人员,要给一次比赛活动获奖的500名选手制作奖状,并...【详细内容】
2024-03-26  Search: python  点击:(18)  评论:(0)  加入收藏
Python实现工厂模式、抽象工厂,单例模式
工厂模式是一种常见的设计模式,它可以帮助我们创建对象的过程更加灵活和可扩展。在Python中,我们可以使用函数和类来实现工厂模式。一、Python中实现工厂模式工厂模式是一种常...【详细内容】
2024-03-07  Search: python  点击:(34)  评论:(0)  加入收藏
不可不学的Python技巧:字典推导式使用全攻略
Python的字典推导式是一种优雅而强大的工具,用于创建字典(dict)。这种方法不仅代码更加简洁,而且执行效率高。无论你是Python新手还是有经验的开发者,掌握字典推导式都将是你技能...【详细内容】
2024-02-22  Search: python  点击:(35)  评论:(0)  加入收藏
如何进行Python代码的代码重构和优化?
Python是一种高级编程语言,它具有简洁、易于理解和易于维护的特点。然而,代码重构和优化对于保持代码质量和性能至关重要。什么是代码重构?代码重构是指在不改变代码外部行为的...【详细内容】
2024-02-22  Search: python  点击:(36)  评论:(0)  加入收藏
Python开发者必备的八个PyCharm插件
在编写代码的过程中,括号几乎无处不在,以至于有时我们会拼命辨别哪个闭合括号与哪个开头的括号相匹配。这款插件能帮助解决这个众所周知的问题。前言在PyCharm中浏览插件列表...【详细内容】
2024-01-26  Search: python  点击:(89)  评论:(0)  加入收藏
Python的Graphlib库,再也不用手敲图结构了
Python中的graphlib库是一个功能强大且易于使用的工具。graphlib提供了许多功能,可以帮助您创建、操作和分析图形对象。本文将介绍graphlib库的主要用法,并提供一些示例代码和...【详细内容】
2024-01-26  Search: python  点击:(88)  评论:(0)  加入收藏
大语言模型插件功能在携程的Python实践
作者简介成学,携程高级安全研发工程师,关注Python/Golang后端开发、大语言模型等领域。一、背景2023年初,科技圈最火爆的话题莫过于大语言模型了,它是一种全新的聊天机器人模型,...【详细内容】
2024-01-26  Search: python  点击:(76)  评论:(0)  加入收藏
▌简易百科推荐
一篇文章教会你使用Python中三种简单的函数
所谓函数,就是指:把某些特定功能的代码组成为一个整体,这个整体就叫做函数。一、函数简介所谓函数,就是指:把某些特定功能的代码组成为一个整体,这个整体就叫做函数。二、函数定义...【详细内容】
2024-04-11  Go语言进阶学习  微信公众号  Tags:Python   点击:(5)  评论:(0)  加入收藏
一篇文章带你了解Python的分布式进程接口
在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。一、前言在Thread和Process中,应当优...【详细内容】
2024-04-11  Go语言进阶学习    Tags:Python   点击:(2)  评论:(0)  加入收藏
Python 可视化:Plotly 库使用基础
当使用 Plotly 进行数据可视化时,我们可以通过以下示例展示多种绘图方法,每个示例都会有详细的注释和说明。1.创建折线图import plotly.graph_objects as go# 示例1: 创建简单...【详细内容】
2024-04-01  Python技术    Tags:Python   点击:(8)  评论:(0)  加入收藏
Python 办公神器:教你使用 Python 批量制作 PPT
介绍本文将介绍如何使用openpyxl和pptx库来批量制作PPT奖状。本文假设你已经安装了python和这两个库。本文的场景是:一名基层人员,要给一次比赛活动获奖的500名选手制作奖状,并...【详细内容】
2024-03-26  Python技术  微信公众号  Tags:Python   点击:(18)  评论:(0)  加入收藏
Python实现工厂模式、抽象工厂,单例模式
工厂模式是一种常见的设计模式,它可以帮助我们创建对象的过程更加灵活和可扩展。在Python中,我们可以使用函数和类来实现工厂模式。一、Python中实现工厂模式工厂模式是一种常...【详细内容】
2024-03-07  Python都知道  微信公众号  Tags:Python   点击:(34)  评论:(0)  加入收藏
不可不学的Python技巧:字典推导式使用全攻略
Python的字典推导式是一种优雅而强大的工具,用于创建字典(dict)。这种方法不仅代码更加简洁,而且执行效率高。无论你是Python新手还是有经验的开发者,掌握字典推导式都将是你技能...【详细内容】
2024-02-22  子午Python  微信公众号  Tags:Python技巧   点击:(35)  评论:(0)  加入收藏
如何进行Python代码的代码重构和优化?
Python是一种高级编程语言,它具有简洁、易于理解和易于维护的特点。然而,代码重构和优化对于保持代码质量和性能至关重要。什么是代码重构?代码重构是指在不改变代码外部行为的...【详细内容】
2024-02-22  编程技术汇    Tags:Python代码   点击:(36)  评论:(0)  加入收藏
Python开发者必备的八个PyCharm插件
在编写代码的过程中,括号几乎无处不在,以至于有时我们会拼命辨别哪个闭合括号与哪个开头的括号相匹配。这款插件能帮助解决这个众所周知的问题。前言在PyCharm中浏览插件列表...【详细内容】
2024-01-26  Python学研大本营  微信公众号  Tags:PyCharm插件   点击:(89)  评论:(0)  加入收藏
Python的Graphlib库,再也不用手敲图结构了
Python中的graphlib库是一个功能强大且易于使用的工具。graphlib提供了许多功能,可以帮助您创建、操作和分析图形对象。本文将介绍graphlib库的主要用法,并提供一些示例代码和...【详细内容】
2024-01-26  科学随想录  微信公众号  Tags:Graphlib库   点击:(88)  评论:(0)  加入收藏
Python分布式爬虫打造搜索引擎
简单分布式爬虫结构主从模式是指由一台主机作为控制节点负责所有运行网络爬虫的主机进行管理,爬虫只需要从控制节点那里接收任务,并把新生成任务提交给控制节点就可以了,在这个...【详细内容】
2024-01-25  大雷家吃饭    Tags:Python   点击:(59)  评论:(0)  加入收藏
站内最新
站内热门
站内头条