在此示例中,`eval()` 为何不是 'dangerous'
How `eval()` is not 'dangerous' in this example
我正在检查一个计算器示例,在示例中使用了 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
是一个字符串,我们正在添加数字和符号,如 4+5
。然后 eval()
处理它。
之所以这是一种更安全的执行 eval() 的方法,是因为它明确限制了允许哪些内置方法(在本例中为 none)。您可以使用该参数来指定任何允许的内置函数。 Here 是关于该主题的更多信息
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 在 , a safer approach would be to use ast.literal_eval
中提到的那样,它就是为此而制作的。作为一般规则:最好使用功能最弱的命令来完成工作,而不是使用功能强大的命令并尝试手动限制它。忘记的东西太多了。
代码一点都不安全。仅通过访问文字的属性就可以相对容易地访问 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__
是 shorthand 对于 object
object.__subclasses__()
列出解释器中 object
的所有子classes(这包括导入机器 使用的 classes
[klass for klass in ... if klass.__name__ == "BuiltinImporter"][0]
-- select BuiltinImporter
class.
load_module("builtins")
使用 BuiltinImporter
获得对 builtins
模块的访问权限——这正是您试图限制访问的内容。
我正在检查一个计算器示例,在示例中使用了 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
是一个字符串,我们正在添加数字和符号,如 4+5
。然后 eval()
处理它。
之所以这是一种更安全的执行 eval() 的方法,是因为它明确限制了允许哪些内置方法(在本例中为 none)。您可以使用该参数来指定任何允许的内置函数。 Here 是关于该主题的更多信息
eval(expression, globals=None, locals=None)
The
expression
argument is parsed and evaluated as a Python expression using theglobals
andlocals
dictionaries as global and local namespace. If theglobals
dictionary is present and lacks'__builtins__'
, the current globals are copied intoglobals
beforeexpression
is parsed. This means thatexpression
normally has full access to the standardbuiltins
module and restricted environments are propagated. If thelocals
dictionary is omitted it defaults to theglobals
dictionary. If both dictionaries are omitted, the expression is executed in the environment whereeval()
is called.
所以您显示的代码的尝试是 eval
在没有潜在危险函数可用的上下文中的表达式。例如,eval('print("bad stuff")')
将打印错误内容,但如果您传递一个空的全局命名空间,即使没有内置 print
.
不要把这种安全感想得太过分。即使在这些限制范围内,不受信任的代码也会破坏您的程序。例如,以下字符串 if eval()
d 会因超出其递归堆栈而使您的 Python 解释器崩溃:
(lambda f : f(f))(lambda f : f(f))
正如 Håken Lid 在 ast.literal_eval
中提到的那样,它就是为此而制作的。作为一般规则:最好使用功能最弱的命令来完成工作,而不是使用功能强大的命令并尝试手动限制它。忘记的东西太多了。
代码一点都不安全。仅通过访问文字的属性就可以相对容易地访问 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__
是 shorthand 对于object
object.__subclasses__()
列出解释器中object
的所有子classes(这包括导入机器 使用的 classes
[klass for klass in ... if klass.__name__ == "BuiltinImporter"][0]
-- selectBuiltinImporter
class.load_module("builtins")
使用BuiltinImporter
获得对builtins
模块的访问权限——这正是您试图限制访问的内容。