我只是很好奇这是否是一种风险,我想不出一种用户可能会导致这种情况发生的方法……但似乎令人担忧。
>>> import ast
>>> help(ast.literal_eval)
Help on function literal_eval in module ast:
literal_eval(node_or_string)
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the following
Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
and None.
ast.literal_eval(f'{os.remove("dontdelete.txt")-hello-world}')
将执行文件删除。有可能将其用于应用程序吗?
“安全评估表达式节点”
是平均值?
答案 0 :(得分:1)
以这种方式定义literal_eval
的原因是,它是ast
模块中的专用功能,而不是旨在用于其他各种目的的魔术功能,因此您应该期待如果使用的话,至少要摘录ast
文档。
literal_eval
可以采用表示已解析表达式的ast.Node
,也可以采用字符串(当赋予ast,parse
时产生这样的节点)。
然后,只要表达式仅使用“以下Python文字结构:字符串,字节,数字,元组,列表,字典,集合,布尔值和None
”,它将对表达式求值;否则,将引发错误。
因此,如果将字符串'os.remove("dontdelete.txt")-hello-world'
传递给它,那么当您解析它时,将得到一个BinOp
表达式,它不是literal_eval
的表达式节点之一接受,因此它立即以ValueError
拒绝它。
如果将其传递给字符串"""f'{os.remove("dontdelete.txt")-hello-world}'"""
,则在解析该字符串时,会得到一个JoinedStr
表达式节点,其中包含一堆literal_eval
也不接受的节点(如果您不了解f字符串的工作原理,则值得进行ast.dump
来确切地了解那些节点是什么),因此将再次使用ValueError
拒绝它。
但是,如果您将其传递给字符串f'{os.remove("dontdelete.txt")-hello-world}'
,该怎么办?
好吧,该字符串在甚至传递给literal_eval
之前就已经由解释器求值。
在大多数情况下,这甚至会在调用literal_eval
之前引发一个异常,因此literal_eval
完全无关紧要。例如:
os
,则会得到NameError
。FileNotFoundError
。hello
或world
不存在,您将获得NameError
。hello
存在但属于任何普通类型的值,因为remove
返回None
,那么您将获得TypeError
来尝试减去任何类型的hello
来自None
。在某些情况下,当然会删除文件。但是由于literal_eval
从未被调用,因此在这里几乎没有意义。您可以使用print
而不是literal_eval
做同样的事情,或者什么都不做。
但是如果导入了os
并且文件存在,并且hello
是某种类型的实例,并且其中的__rsub__
接受None
,并且{{1 }}是某种类型的实例,可以将其传递给返回的任何world
的{{1}}吗?然后__sub__
将返回hello.__rsub__
返回的任何内容。如果是字符串或literal_eval
,它甚至会求值。也许那将是其他一些危险的字符串?但是在那种情况下,sub
会在那个危险的字符串上引起ast.Node
,因此不会造成额外的伤害。