在这个例子中,eval()`如何不是“危险的”

2024-05-29 10:34:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我在检查一个计算器的例子,在这个例子中使用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()处理它。在


Tags: thenoneifcheckevalbutton计算器例子
3条回答

密码一点也不安全。只需访问文本的属性就可以相对容易地访问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__()列出解释器中{}的所有子类(这包括导入机制使用的类)
  • [klass for klass in ... if klass.__name__ == "BuiltinImporter"][0]选择BuiltinImporter类。在
  • load_module("builtins")使用BuiltinImporter访问builtins模块,这正是您试图限制访问的地方。在

之所以这是一种更安全的eval()执行方法,是因为它显式地限制了允许哪些内置方法(在本例中不允许)。可以使用该参数指定允许的任何内置项。Here是关于这个主题的更多信息

根据the documentation of ^{}

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

The expression argument is parsed and evaluated as a Python expression using the globals and locals dictionaries as global and local namespace. If the globals dictionary is present and lacks '__builtins__', the current globals are copied into globals before expression is parsed. This means that expression normally has full access to the standard builtins module and restricted environments are propagated. If the locals dictionary is omitted it defaults to the globals dictionary. If both dictionaries are omitted, the expression is executed in the environment where eval() is called.

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

别把这种安全感看得太过分。不受信任的代码也可以共享您的程序,即使在这些限制内。例如,以下字符串if eval()d将通过超出其递归堆栈使Python解释器崩溃:

(lambda f : f(f))(lambda f : f(f))

正如Håken Lid在his comment中提到的,一个更安全的方法是使用^{},这正是为此而设计的。一般来说,最好是使用功能最弱的命令来完成任务,而不是使用功能强大的命令并尝试手动限制它。有太多的事情你可以忘记。在

相关问题 更多 >

    热门问题