如何将 exec 的输出设置为 Python 变量?

7

我正在尝试使用Python设置客户端和服务器,以便客户端发送一些代码,服务器执行和处理它,然后发送输出。我可以使用exec命令在服务器上执行接收到的代码,但每当我尝试var = exec "print 'word'"时,它都无法正常工作并且失败,显示语法错误;而当我运行相同的命令而不设置变量时,它能够无缝运行。我正在使用Python2.7。

2个回答

10

不要使用eval和exec,它们对于不可信的输入非常危险,而且没有合理的方法可以使它们安全:

从不可信的输入中使用evalexec意味着您可能会得到这样的查询:

eval("os.system('clear')", {})

使用ast.literal_eval安全地将字符串转换为Python对象。
>>> import ast
>>> string = '{}'
>>> b = ast.literal_eval(string)
>>> b
{}
>>> type(b)
<class 'dict'>

如果你可以信任输入,使用eval

>>> string = '{}'
>>> b = eval(string)
>>> b
{}
>>> type(b)
<class 'dict'>

Eval和Exec的危险性

为了解释为什么eval是危险的,以及为什么ast.literal_eval是安全的,你需要了解eval的工作原理:它只是将一个字符串解释为Python代码,允许发生基本上任何事情。

有许多方法可以尝试使evalexec安全,但是所有这些方法都有各种绕过它们的方式。你可以防止几乎一切,包括导入、内置函数等等,但是某些人仍然可以找到绕过它们的方法(参见上面的链接)。

ast.literal_eval通过允许评估有效的Python数据类型(例如dict、list、tuple、None、int、string和float)来避免这种情况。这可以防止任何代码的恶意执行,但应用程序的功能要受到更大的限制。然而,对于来自未知来源的代码来说,这种额外的安全性是非常值得失去功能的。

ast.literal_eval如何保护你的安全的一个很好的例子是以下片段:

>>> import ast
>>> eval('__import__("os")')
<module 'os' from '/usr/lib/python3.4/os.py'>

>>> ast.literal_eval('__import__("os")')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.4/ast.py", line 84, in literal_eval
    return _convert(node_or_string)
  File "/usr/lib/python3.4/ast.py", line 83, in _convert
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x7f68e03db2e8>

Eval允许直接执行代码,这样可以访问os模块并执行系统任务,可能会擦除您的驱动器,而ast.literal_eval会引发错误,因为它不是一个被识别的数据类型。

你说os.system('clear')很糟糕。它到底是做什么的? - Toothpick Anemone
@ToothpickAnemone 这个命令本身并没有危害,它只是清空终端而已。然而,这表明了一个更为严重的现象:拥有os.system访问权限的人可以轻松地擦除您的硬盘或者更糟的情况。这个命令本意是无害的,因为我不想让别人复制粘贴代码时不小心把自己的数据给擦除了。 - Alex Huszagh

2

您可以在exec语句中设置变量:

>>> exec("var = 'hello'")
>>> var
'hello'

2
这不会起作用,因为我发送的代码字符串并不总是一个打印语句。让我解释一下:客户端发送“print 'this'”...服务器接收到"print 'this'"并需要执行接收到的字符串,并将输出发送回客户端...客户端应该接收到“this”。 - Eli Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接