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

Posted

技术标签:

【中文标题】在 python Web 服务器上执行数学用户代码,最简单的安全方法是啥?【英文标题】:Executing mathematical user code on a python web server, what is the simplest secure way?在 python Web 服务器上执行数学用户代码,最简单的安全方法是什么? 【发布时间】:2012-05-25 17:01:41 【问题描述】:

我知道以前有人问过这个问题,但是这个案例略有不同。

我想运行一个 python 图像板(使用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 的一个子集(解析和白名单?),还是我可以嵌入的面向数学的语言?

【问题讨论】:

我实际上会使用 PyPy 沙箱。 我读过的其他几个答案都投了反对票......所以我还没有真正研究过 PyPy - 我会检查一下谢谢 好问题,也许 PyPy 就是答案。今天只是在谈论与 lua 相比,Python 在这里可能有点短。 如果你有时间,我认为使用 python 的内部编译器自己开发会很有趣:***.com/questions/594266/equation-parsing-in-python 哇...我正在考虑构建自己的语言(目前正在为 uni 赋值编写 PL0 编译器),但这种方式可能会更有趣! 【参考方案1】:

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

【讨论】:

【参考方案2】:

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

Restricting Python's syntax to execute user code safely. Is this a safe approach?

感谢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 子集;非常适合用户脚本!

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

【讨论】:

这应该是一个独立的问题 IMO。 对不起。我知道有人可以帮我检查一下;如果他觉得没问题,我会重新格式化它,让它更像一个答案。 (否则我会删除它)。 我的意思是:如果你把这个答案转换成一个新问题,你会得到更多的关注(可能还有新的建议):) 移至***.com/questions/10661079/…

以上是关于在 python Web 服务器上执行数学用户代码,最简单的安全方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

将你的Python Web程序部署到Ubuntu服务器上

GitLab Runner:在没有外壳的情况下切换用户后在服务器上执行代码

WEB开发原则

Python学起,工资飞起

Python web 开发用户注册功能

git部署