我正在检查计算器示例,在使用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()
处理它。
答案 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)
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是关于该主题的更多信息