原始问题:
在 python Web 服务器上执行数学用户代码,最简单的安全方法是什么?
- 我希望能够在 python 网络服务器上运行用户提交的代码。代码本质上将是简单和数学的。
由于需要这么小的 Python 子集,我目前的方法是通过遍历 Python 的抽象语法树来将允许的语法列入白名单。函数和名称得到特殊处理;只允许明确列入白名单的函数,并且只允许未使用的名称。
import ast
allowed_functions = set([
#math library
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh',
'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf',
'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod',
'frexp', 'fsum', 'gamma', 'hypot', 'isinf', 'isnan', 'ldexp',
'lgamma', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians',
'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc',
#builtins
'abs', 'max', 'min', 'range', 'xrange'
])
allowed_node_types = set([
#Meta
'Module', 'Assign', 'Expr',
#Control
'For', 'If', 'Else',
#Data
'Store', 'Load', 'AugAssign', 'Subscript',
#Datatypes
'Num', 'Tuple', 'List',
#Operations
'BinOp', 'Add', 'Sub', 'Mult', 'Div', 'Mod', 'Compare'
])
safe_names = set([
'True', 'False', 'None'
])
class SyntaxChecker(ast.NodeVisitor):
def check(self, syntax):
tree = ast.parse(syntax)
self.visit(tree)
def visit_Call(self, node):
if node.func.id not in allowed_functions:
raise SyntaxError("%s is not an allowed function!"%node.func.id)
else:
ast.NodeVisitor.generic_visit(self, node)
def visit_Name(self, node):
try:
eval(node.id)
except NameError:
ast.NodeVisitor.generic_visit(self, node)
else:
if node.id not in safe_names and node.id not in allowed_functions:
raise SyntaxError("%s is a reserved name!"%node.id)
else:
ast.NodeVisitor.generic_visit(self, node)
def generic_visit(self, node):
if type(node).__name__ not in allowed_node_types:
raise SyntaxError("%s is not allowed!"%type(node).__name__)
else:
ast.NodeVisitor.generic_visit(self, node)
if __name__ == '__main__':
x = SyntaxChecker()
while True:
try:
x.check(raw_input())
except Exception as e:
print e
这似乎接受了所需的语法,但我对编程相当陌生,可能会遗漏任何数量的安全漏洞。
所以我的问题是:这是否安全,是否有更好的方法,还有我应该采取的其他预防措施吗?