解析,在将python表达式传递给eval()之前保护它

时间:2010-01-14 15:43:53

标签: python

我想从用户那里获得一个输入可能就像foo() > 90 and boo() == 9 or do() > 100并在服务器端使用eval来评估这个表达式。

为了安全起见,我想通过在将其传递给eval函数之前检查(针对某些数据结构)来限制用户添加有限的函数和运算符。

PS:输入来自网页

由于

4 个答案:

答案 0 :(得分:3)

基本上,唯一的方法是自己解析它。您可以导航解析树以确保每个部分都处于完美良性和安全操作的白名单中,从而使整个表达式通过构造安全。 Ned Batchelder的答案实际上是一种(简单)形式。在那之后你可以将它传递给eval(),但是,重点是什么?您可以计算每个子表达式的值作为验证的一部分(这尤其是一个好主意,因为它使您的解析器能够抵抗Python语法中的更改等)。这个白名单必须非常小,并且你可能认为很多东西都可以,但不是(例如一般呼叫操作员; getattr功能)。你必须非常小心。

黑名单绝对不可能(例如“拒绝可疑条目”的建议)。拒绝任何明显不好的东西。如果你不这样做,那么解决你的过滤器并给出一个表达不好的表达将是微不足道的,除非你的代码不太可能比任何其他Python创建的黑名单过滤器更好。

有人试图限制Python执行,一个是臭名昭着的,现在已经被禁用(因为它不起作用)rexec模块(和公司),另一个是PyPy's sandbox。第二个选项并不完全符合您的要求,但它肯定值得研究。这可能就是我要用的东西 - 它只是意味着它不会像eval(safematize(user_input))那么容易。

答案 1 :(得分:1)

更安全的方法是在后端做所有事情。用户只需输入必要的参数即可。例如,您可以提示他们键入foo(),boo()和do()的数值。然后在后端,将这些值传递给适当的函数以进行计算。

答案 2 :(得分:1)

也许最简单的检查是查看表达式中的所有单词,并针对白名单进行检查。如果白名单中没有任何单词,则拒绝表达式。

import re

expr = "foo() > 90 and boo() == 9 or do() > 100"
whitelist = "and or foo boo do".split()
for word in re.findall(r"[a-zA-Z_]\w+", expr):
    if word not in whitelist:
        raise Exception("Warning! Warning!")

这是有效的,因为你有一个有限的域,你需要用户能够表达自己,并且因为我认为没有办法在不使用标识符的情况下使用eval造成损害。

但是,您必须小心,您的白名单不会无意中包含可能的恶意Python标识符。

答案 3 :(得分:1)

您需要锁定输入格式,否则将是一个巨大的安全漏洞。正如lpthnc建议的那样,实现一个完整的解析器,使用一组合理的操作(但不多),或者至少使用正则表达式(或匹配层次结构和/或循环中的几个正则表达式模式)来去除已识别的模式,拒绝可疑条目为“不允许”。