>> exec(cod"/>
我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用 exec 函数时需要注意的一些安

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用 exec 函数时需要注意的一些安

众所周知,在 python 中可以使用 exec 函数来执行包含 python 源代码的字符串:

>>> code = '''
   ...: a = "hello"
   ...: print(a)
   ...: '''
>>> exec(code)
hello
>>> a
'hello'

exec 函数的这个功能很是强大,慎用。如果一定要用的话,那么就需要注意一下下面这些安全相关的问题。

全局变量和内置函数

exec 执行的代码中,默认可以访问执行 exec 时的局部变量和全局变量, 同样也会修改全局变量。如果 exec 执行的代码是根据用户提交的数据生产的话,这种默认行为就是一个安全隐患。

如何更改这种默认行为呢?可以通过执行 exec 函数的时候再传两个参数的方式来 修改这种行为(详见 之前 关于 exec 的文章):

>>> g = {}
>>> l = {'b': 'world'}
>>> exec('hello = "hello" + b', g, l)
>>> l
{'b': 'world', 'hello': 'helloworld'}
>>> g
{'__builtins__': {...}}
>>> hello
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
...
NameError: name 'hello' is not defined

如果要限制使用内置函数的话,可以在 globals 参数中定义一下 __builtins__ 这个 key:

>>> g = {}
>>> l = {}
>>> exec('a = int("1")', g, l)
>>> l
{'a': 1}

>>> g = {'__builtins__': {}}
>>> exec('a = int("1")', g, l)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'int' is not defined
>>>

现在我们限制了访问和修改全局变量以及使用内置函数,难道这样就万事大吉了吗? 然而并非如此,还是可以通过其他的方式来获取内置函数甚至 os.system 函数。

另辟蹊径获取内置函数和 os.system

通过函数对象:

>>> def a(): pass
...
>>> a.__globals__['__builtins__']

>>> a.__globals__['__builtins__'].open
<built-in function open>

通过内置类型对象:

>>> for cls in {}.__class__.__base__.__subclasses__():
...     if cls.__name__ == 'WarningMessage':
...         b = cls.__init__.__globals__['__builtins__']
...         b['open']
...
<built-in function open>
>>>

获取 os.system:

>>> cls = [x for x in [].__class__.__base__.__subclasses__() if x.__name__ == '_wrap_close'][0]
>>> cls.__init__.__globals__['path'].os
<module 'os' from '/usr/local/var/pyenv/versions/3.5.1/lib/python3.5/os.py'>
>>>

对于这两种办法又如何应对呢? 一种办法就是禁止访问以 _ 开头的属性:

  • 如果可以控制 code 的生成,那么就在生成 code 的时候判断

  • 如果不能的话,可以通过 dis 模块分析生成的 code (dist 无法分析嵌套函数的代码)

  • 使用 tokenize 模块:

    In [68]: from io import BytesIO
    In [69]: code = '''
       ....: a = 'b'
       ....: a.__str__
       ....: def b():
       ....:     b.__get__
       ....: '''
    In [70]: t = tokenize(BytesIO(code.encode()).readline)
    In [71]: for x in t:
       ....:     print(x)
       ....:
    TokenInfo(type=59 (ENCODING), string='utf-8', start=(0, 0), end=(0, 0), line='')
    TokenInfo(type=58 (NL), string='\n', start=(1, 0), end=(1, 1), line='\n')
    TokenInfo(type=1 (NAME), string='a', start=(2, 0), end=(2, 1), line="a = 'b'\n")
    TokenInfo(type=53 (OP), string='=', start=(2, 2), end=(2, 3), line="a = 'b'\n")
    TokenInfo(type=3 (STRING), string="'b'", start=(2, 4), end=(2, 7), line="a = 'b'\n")
    TokenInfo(type=4 (NEWLINE), string='\n', start=(2, 7), end=(2, 8), line="a = 'b'\n")
    TokenInfo(type=1 (NAME), string='a', start=(3, 0), end=(3, 1), line='a.__str__\n')
    TokenInfo(type=53 (OP), string='.', start=(3, 1), end=(3, 2), line='a.__str__\n')
    TokenInfo(type=1 (NAME), string='__str__', start=(3, 2), end=(3, 9), line='a.__str__\n')
    TokenInfo(type=4 (NEWLINE), string='\n', start=(3, 9), end=(3, 10), line='a.__str__\n')
    TokenInfo(type=1 (NAME), string='def', start=(4, 0), end=(4, 3), line='def b():\n')
    TokenInfo(type=1 (NAME), string='b', start=(4, 4), end=(4, 5), line='def b():\n')
    TokenInfo(type=53 (OP), string='(', start=(4, 5), end=(4, 6), line='def b():\n')
    TokenInfo(type=53 (OP), string=')', start=(4, 6), end=(4, 7), line='def b():\n')
    TokenInfo(type=53 (OP), string=':', start=(4, 7), end=(4, 8), line='def b():\n')
    TokenInfo(type=4 (NEWLINE), string='\n', start=(4, 8), end=(4, 9), line='def b():\n')
    TokenInfo(type=5 (INDENT), string='    ', start=(5, 0), end=(5, 4), line='    b.__get__\n')
    TokenInfo(type=1 (NAME), string='b', start=(5, 4), end=(5, 5), line='    b.__get__\n')
    TokenInfo(type=53 (OP), string='.', start=(5, 5), end=(5, 6), line='    b.__get__\n')
    TokenInfo(type=1 (NAME), string='__get__', start=(5, 6), end=(5, 13), line='    b.__get__\n')
    TokenInfo(type=4 (NEWLINE), string='\n', start=(5, 13), end=(5, 14), line='    b.__get__\n')
    TokenInfo(type=6 (DEDENT), string='', start=(6, 0), end=(6, 0), line='')
    TokenInfo(type=0 (ENDMARKER), string='', start=(6, 0), end=(6, 0), line='')

从上面的输出我们可以知道当 type 是 OP 并且 string 等于 '.' 时,下一条记录就是
点之后的属性名称。所以我们的检查代码可以这样写:


    import io
    import tokenize


    def check_unsafe_attributes(string):
        g = tokenize.tokenize(io.BytesIO(string.encode('utf-8')).readline)
        pre_op = ''
        for toktype, tokval, _, _, _ in g:
            if toktype == tokenize.NAME and pre_op == '.' and tokval.startswith('_'):
                attr = tokval
                msg = "access to attribute '{0}' is unsafe.".format(attr)
                raise AttributeError(msg)
            elif toktype == tokenize.OP:
                pre_op = tokval

我所知道的使用 exec 函数时需要注意的安全问题就是这些了。 如果你还知道其他需要注意的安全问题的话,欢迎留言告知。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用 exec 函数时需要注意的一些安

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

使用 exec 函数时需要注意的一些安

众所周知,在 python 中可以使用 exec 函数来执行包含 python 源代码的字符串:>>> code = ''' ...: a = "hello" ...: print(a) ...: '''>>> exec(cod
2023-01-31

在python中使用匿名函数时需要注意哪些问题

在python中使用匿名函数时需要注意哪些问题?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python可以做什么Python是一种编程语言,内置了许多有效的工
2023-06-14

在python中使用zip函数时需要注意的事项

在python中使用zip函数时需要注意的事项?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python可以做什么Python是一种编程语言,内置了许多有效的工
2023-06-14

使用 C++ 内联函数需要注意哪些事项?

c++++内联函数在编译时直接展开,避免函数调用开销。事项包括:1. 函数体小(建议10行以内);2. 避免循环和递归;3. 注意内联展开仅在同文件范围内。实战案例中,计算三角形面积的内联函数替换了普通函数,减少了函数调用开销,提升了程序性
使用 C++ 内联函数需要注意哪些事项?
2024-04-16

使用 STL 函数对象需要注意哪些陷阱?

stl函数对象使用陷阱:不可修改函数对象的状态,否则可能导致后果或崩溃。函数对象应作为右值使用,左值使用会导致未定义行为。捕获局部变量时应确保捕获所有引用的变量,否则可能导致崩溃。使用 STL 函数对象需要注意的陷阱STL 函数对象是一个
使用 STL 函数对象需要注意哪些陷阱?
2024-04-25

C++指针作为函数的参数进行传递时需要注意的一些问题

当指针作为函数的参数进行传递的时候,本质上还是进行的“值传递”,也就是复制了一个新的指向该地址的指针变量
2022-11-15

PHP 函数处理数据时,需要注意哪些常见错误?

处理 php 数据时,常见错误包括:使用 unset() 而不是 empty() 和 isset();混淆 == 和 ===;忘记过滤用户输入和转义输出;错误处理数组。避免这些错误可提升代码质量,防止安全漏洞和执行错误。处理数据时 PHP
PHP 函数处理数据时,需要注意哪些常见错误?
2024-05-04

使用Java构造器时需要注意哪些事项

今天就跟大家聊聊有关使用Java构造器时需要注意哪些事项,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java构造器使用方法及注意事项超类的构造器在子类的构造器运行之前运行,也就是说
2023-05-31

在java中使用static时需要注意哪些问题

在java中使用static时需要注意哪些问题?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1、使用static方法的时候,只能访问static声明的属性和方法,而非stati
2023-06-06

在Java8中使用Stream时需要注意哪些事项

在Java8中使用Stream时需要注意哪些事项?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Stream简介Stream是元素的集合,这点让Stream看起来用些类似It
2023-05-30

在java中使用subList时需要注意哪些问题

在java中使用subList时需要注意哪些问题?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. 使用Arrays.asList的注意事项1.1 可能会踩的坑先来看下Ar
2023-06-06

在python中使用lxml时需要注意哪些事项

这篇文章将为大家详细讲解有关在python中使用lxml时需要注意哪些事项,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python主要应用领域有哪些1、云计算,典型应用OpenStack。
2023-06-14

在java中使用Sorted时需要注意哪些问题

这期内容当中小编将会给大家带来有关在java中使用Sorted时需要注意哪些问题,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用
2023-06-14

在java中使用final时需要注意哪些事项

在java中使用final时需要注意哪些事项?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java的特点有哪些Java的特点有哪些1.Java语言作为静态面向对象编程语言的代表
2023-06-14

在python中使用yield时需要注意哪些事项

在python中使用yield时需要注意哪些事项?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比
2023-06-14

在python中使用os.remove()时需要注意哪些问题

在python中使用os.remove()时需要注意哪些问题?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python可以做什么Python是一种编程语言,内置
2023-06-14

在python中使用可变参数时需要注意哪些事项

在python中使用可变参数时需要注意哪些事项?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python主要应用领域有哪些1、云计算,典型应用OpenStack
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录