我想让用户在给定一些参数的情况下输入计算公式。在没有安全漏洞的情况下,最好的方法是什么?
有点像这样:
def generate_bills():
land_size = 100
building_size = 200
class = 1
formula = "(0.8*land_size)+building_size+(if class==1 10 else if class==2 5 else 2)"
bill = calculate(formula,{'land_size':land_size,'building_size':building_size})
答案 0 :(得分:0)
最简单的方法是清理输入。基本上,您只想关注您定义的参数并丢弃其他所有参数。数值方程式的卫生遵循几个简单的步骤:
ast
或eval
时可能会出现问题。这是一个非常强大的消毒剂,我改编自另一个项目。代码如下,但这里有一些示例输入和输出:
在理想情况下,输入和输出是相同的:
enter func: building_size*40+land_size*20-(building_size+land_size)
building_size*40+land_size*20-(building_size+land_size)
但是,如果用户使用空格/句点/制表符/甚至换行符(喘气),输出仍然很漂亮:
enter func:
building_size * 500 + land_size-20+building_size.
building_size*500+land_size-20+building_size
无论用户尝试何种误导,恶意注入,输入都非常干净:
enter func: land_size + 2 * building_size quit()
land_size+2*building_size
enter func: 1337+land_size h4x'; DROP TABLE members;
1337+land_size
更重要的是,您可以非常轻松修改功能,以便在消毒后将实际值输入等式中。我的意思是从land_size+2*building_size
到100+2*200
使用简单的replace
语句。这样,您的功能就可以eval
和ast
{/ 3}} parseable。{/ p>
代码如下:
import re
# find all indices of a given char
def find_spans(ch, s):
return [tuple((i, i+1)) for i, ltr in enumerate(s) if ltr == ch]
# check to see if an unknown is a number
def is_number(s):
try:
float(s)
except:
return False
return True
# these are the params you will allow
# change these to add/remove parameters/operators
allowed_params = ['land_size', 'building_size']
operators = ['+', '-', '*', '/', '(', ')']
# get input
in_formula = raw_input('enter func: ')
# dictionary that will hold every allowed function element found in the input and its position(s)
found_params = {}
# extract param indices
for param in allowed_params:
found_params[param] = [i.span() for i in re.finditer(param, in_formula)]
# extract operator indices
for op in operators:
found_params[op] = find_spans(op,in_formula)
# get all index regions that are "approved", that is, they are either a param or operator
allowed_indices = sorted([j for i in found_params.values() for j in i])
# these help remove anything unapproved at beginning or end
allowed_indices.insert(0,(0,0))
allowed_indices.append((len(in_formula),len(in_formula)))
# find all index ranges that have not been approved
unknown_indices = [(allowed_indices[i-1][1], allowed_indices[i][0]) for i in range(1,len(allowed_indices)) if allowed_indices[i][0] <> allowed_indices[i-1][1]]
# of all the unknowns, check to see if any are numbers
numbers_indices = [(''.join(in_formula[i[0]:i[1]].split()),i) for i in unknown_indices if is_number(in_formula[i[0]:i[1]])]
# add these to our final dictionary
for num in numbers_indices:
try:
found_params[num[0]].append(num[1])
except:
found_params[num[0]] = [num[1]]
# get final order of extracted parameters
final_order = sorted([(i[0],key) for key in found_params.keys() for i in found_params[key]])
# put all function elements back into a string
final_function = ''.join([i[1] for i in final_order])
#
# here you could replace the parameters in the final function with their actual values
# and then evaluate using eval()
#
print final_function
如果有什么事情没有意义,请告诉我,我很乐意解释。