代码之家  ›  专栏  ›  技术社区  ›  Vishal

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

  •  4
  • Vishal  · 技术社区  · 16 年前

    我想从用户的输入可能是这样的 foo() > 90 and boo() == 9 or do() > 100 并在服务器端使用eval来计算这个表达式。

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

    谢谢

    4 回复  |  直到 16 年前
        1
  •  3
  •   Devin Jeanpierre    16 年前

    eval() 不过,在那之后,又有什么意义呢?作为验证的一部分,您可以计算每个子表达式的值(这是一个特别好的主意,因为它使您的解析器能够抵抗Python语法等方面的更改)。这个白名单必须非常小,而且有很多东西你可能认为是好的,但不是(例如,通用调用操作符;getattr函数)。你必须非常小心。

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

    有人试图限制Python的执行,其中一个是臭名昭著的,现在被禁用了(因为它不起作用) rexec 模块(和公司),另一个是 PyPy's sandbox . 第二个选项并不能完全满足您的要求,但它确实值得研究。这可能就是我要用的——它只是意味着它不会像以前那么简单 eval(safematize(user_input))

        2
  •  1
  •   ghostdog74    16 年前

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

        3
  •  1
  •   Ned Batchelder    16 年前

    也许最简单的检查方法是查看表达式中的所有单词,并对照白名单进行检查。如果任何单词不在白名单上,则拒绝该表达式。

    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!")
    

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

        4
  •  1
  •   Roboprog    16 年前

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