在没有eval的情况下在Python 3中安全地解析用户定义的方程式

时间:2015-04-08 05:41:51

标签: python security

我的代码中有许多变量,例如STA,INT,AGI和dmg_taken,并希望dmg_taken由用户定义的等式计算。作为概念证明,我使用了eval,其工作原理如下。

unsafe.py

dmg_min   = eval(self.rules.all_rules['dmg_min'])
dmg_max   = eval(self.rules.all_rules['dmg_max'])

具有等式的外部规则文件看起来像

battle.rules

dmg_min = 2
dmg_max = round(((STR * 1.5) + (AGI * 1.02) + (INT * 1.3)) / 6 )

规则可以是包含程序中使用的任意数量变量的数字或公式 - 有什么更好的方法可以做到这一点?

1 个答案:

答案 0 :(得分:0)

我没有遇到过一种完全安全的方法来解决这个问题。

  1. 用户定义的方程式可以由python代码中的库用户完成(基本上他们可以在控制代码时做他们想做的事情)

  2. 对于外部用户,所有方程式参数都会拆分为变量并以数字形式读取,因此无需进行评估。

  3. 修改规则文件

    dmg_INT_mult = 0.9
    dmg_AGI_mult = 1.2
    dmg_STR_mult = 1.2
    dmg_INT_add = -.5
    dmg_AGI_add = 0
    dmg_STR_add = 0
    dmg_overall_mult = 0.1667
    dmg_overall_add = 0
    

    这些参数用于在battle.py程序中构建等式

    #   dmg_max = round(
    #                    ((STR + dmg_STR_add) * dmg_STR_mult) 
    #                  + ((AGI + dmg_AGI_add) * dmg_AGI_mult) 
    #                  + ((INT + dmg_INT_add) * dmg_INT_mult)
    #                  ) * dmg_overall_mult 
    #             + dmg_overall_add
    

    新代码

    calc_agi = round((AGI + float(self.rules.all_rules['dmg_AGI_add'])) * float(self.rules.all_rules['dmg_AGI_mult']))
    calc_int = round((INT + float(self.rules.all_rules['dmg_INT_add'])) * float(self.rules.all_rules['dmg_INT_mult']))
    calc_str = round((STR + float(self.rules.all_rules['dmg_STR_add'])) * float(self.rules.all_rules['dmg_STR_mult'])) 
    dmg_max = round((calc_agi + calc_int + calc_str) * float(self.rules.all_rules['dmg_overall_mult']) + float(self.rules.all_rules['dmg_overall_add']))
    

    这是安全的,因为读入的所有参数都被转换为浮点数,因此任何字符串都会导致异常,并允许最终用户构建相当复杂的方程式。