在python web服务器上执行数学用户代码,最简单的安全方法是什么?

2024-09-19 14:22:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道以前有人问过这个问题,不过这个案子有点不同。在

我想运行一个python imageboard(使用web.py),它允许用户通过提交代码生成新的图像。代码将采用单个函数的形式,该函数获取像素的x、y坐标并返回r、g、b值,例如:

def simpleGradient(xrel,yrel):
    r = xrel*256
    g = yrel*256
    b = 0
    return [r,g,b]

只需要一个非常小的语法,它不一定是python。使用范围有限的exec似乎太不安全,而使用PyPy或VM似乎不必要地复杂(我对所有这些都很陌生)。在

有没有一种python方法可以用更小的语言来执行代码,而不是用沙箱来处理它?python的一个子集(解析和白名单?),或者我可以嵌入的面向数学的语言?在


Tags: 函数代码用户py图像web语言def
2条回答

有很多很棒的信息on the pysandbox pypi page。在

这就是我的解决方案。有关此方法的安全性的讨论,请参见

多亏了arifwn,我开始研究Python的ast(抽象语法树)模块。此模块提供一个用于遍历树的ast.NodeVisitor。这段代码将NodeVisitor子类化,以创建一个语法检查器,该检查器将基本数学所需的代码白名单。函数调用和名称是特别监视的,因为只允许某些函数,只允许使用未使用的名称。在

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.passed=True
        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

请注意,这是为了只接受代码的数学部分而设计的,提供了函数定义和返回语句。在

这种将所有必需的安全构造(尤其是白名单所需的不安全构造)白名单的方法可以修改为生成许多有用的Python子集;非常适合用户脚本!在

注意,为了安全地执行,它应该在它自己的线程中有一个超时,以便在用户代码生成无限循环或类似循环时减少名称冲突和超时。在

相关问题 更多 >