eval 函数非常危险

原文标题:Eval really is dangerous
原文链接:https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
原文作者:Ned Batchelder
本文地址:https://www.white-winds.com/post/eval really is dangerous/

翻译这篇文章的原因是在业务上很多使用 eval 来进行类型转换,比如 eval("[1,2,3]"),这些代码要么没有对传入的字符串进行过滤,要么就是简单的将 globals 置空 eval("[1,2,3]", {})。本文详细分析了 eval 不安全的原因,如果只是为了类型转换,可以使用 ast.literal_eval 来代替。

Python 的 eval() 函数用于将传入的字符串作为代码进行求值。

Python has an eval() function which evaluates a string of Python code:

assert eval("2 + 3 * len('hello')") == 17

它十分强大,但如果对不可信的字符串进行求值,就会非常危险。比如正在求值的字符串是 os.system('rm-rf /') ?它将真正删除计算机上的所有文件。(在下面的示例中,我将使用 clear 而不是 rm-rf / 以防意外。)

This is very powerful, but is also very dangerous if you accept strings to evaluate from untrusted input. Suppose the string being evaluated is “os.system(‘rm -rf /’)” ? It will really start deleting all the files on your computer. (In the examples that follow, I’ll use ‘clear’ instead of ‘rm -rf /’ to prevent accidental foot-shootings.)

一些人声称可以通过不提供全局变量,使 eval 变得安全。eval 的第二个参数是在求值期间使用的全局变量,为字典形式,如果没有提供,eval 将使用当前的全局变量,进而可以使用 os 模块。如果提供一个空字典,那就没有全局变量,触发异常: NameError: name 'os' is not defined

Some have claimed that you can make eval safe by providing it with no globals. eval() takes a second argument which are the global values to use during the evaluation. If you don’t provide a globals dictionary, then eval uses the current globals, which is why “os” might be available. If you provide an empty dictionary, then there are no globals. This now raises a NameError, “name ‘os’ is not defined”:

eval("os.system('clear')", {
   })

但我们仍然可以通过 builtins 中的函数 __import__ 来引入它们并使用,下面的代码可以执行成功:

But we can still import modules and use them, with the builtin function import. This succeeds:

eval("__import__('os').system('clear')", {
   })

在 Python 2 中可以使用 __import__open 函数的原因是它们位于全局变量 __builtins__ 中,为了确保安全,我们尝试在 eval 中拒绝其访问 builtins。通过在全局变量中将 __builtins__ 定义为空字典,我们可以显式指定不使用这些内置函数。现在下面的代码会抛出 NameError:

The next attempt to make things safe is to refuse access to the builtins. The reason names like _import_ and open are available to you in Python 2 is because they are in the _builtins_ global. We can explicitly specify that there are no builtins by defining that name as an empty dictionary in our globals. Now this raises a NameError:

eval("__import__('os').system('clear')", {
   "__builtins__": {
   }})

!!! note
eval 的函数定义为:eval(expression[, globals[, locals]])
你可能会疑惑,上面已经将 globals 置为 {} 了,为什么还要显式的将

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值