`eval()`如何不危险'在这个例子中

时间:2015-01-22 23:18:49

标签: python eval python-3.4

我正在检查计算器示例,在使用eval()的示例中,这通常是危险的,但这是该示例的一部分;

if button == "=":
    #Check carefully how we using the 'dangerous' eval()
    total = eval(str1,{"__builtins__":None},{})
    str1 = str(total)
    print (str1)

我检查过但我不明白; eval(str1,{"__builtins__":None},{})如何不危险?它显然是{"__builtins__":None},{}这一部分,但我不明白。

注意:str1是一个字符串,我们正在添加数字和smybols,如4+5。然后eval()处理它。

3 个答案:

答案 0 :(得分:7)

代码不是最安全的。只需访问文字属性,就可以相对轻松地访问builtins模块。

例如

result = eval("""[klass for klass in ''.__class__.__base__.__subclasses__()
            if klass.__name__ == "BuiltinImporter"][0].load_module("builtins")""",
    {"__builtins__":None},{})
assert result is __builtins__

细分:

  • ''.__class__.__base__object
  • 的简写
  • object.__subclasses__()列出解释器中object的所有子类(包括导入机器使用的类
  • [klass for klass in ... if klass.__name__ == "BuiltinImporter"][0] - 选择BuiltinImporter类。
  • load_module("builtins")使用BuiltinImporter访问builtins模块 - 您试图限制访问的内容。

答案 1 :(得分:4)

根据the documentation of eval

eval(expression, globals=None, locals=None)
     

expression 参数使用 globals locals来解析和评估为Python表达式词典作为全局和本地命名空间。如果 globals 字典存在且缺少'__builtins__',则在 {{1}之前将当前全局变量复制到 globals 解析了。这意味着 expression 通常具有对标准expression模块的完全访问权限,并且传播受限制的环境。如果省略 builtins 字典,则默认为 locals 字典。如果省略两个字典,则表达式在调用globals的环境中执行。

因此,您展示的代码的尝试是eval()在没有潜在危险函数可用的上下文中的表达式。例如,即使没有内置eval,如果你传递一个空的全局命名空间,eval('print("bad stuff")')也会打印坏内容。

不要把这种安全感太过分了。即使在这些限制范围内,不受信任的代码也可能会破坏您的程序。例如,以下字符串if print d会因超过其递归堆栈而导致Python解释器崩溃:

eval()

正如HåkenLid在his comment中提到的,更安全的方法是使用ast.literal_eval,这是为此而做的。作为一般规则:使用功能最少的命令总是更好,而不是使用功能强大的命令并尝试手动限制它。你可以忘记的事情太多了。

答案 2 :(得分:-1)

这是执行eval()的一种更安全的方法的原因是因为它明确限制了允许哪些内置方法(在这种情况下不是这样)。您可以使用该参数指定允许的任何内置函数。 Here是关于该主题的更多信息