在 python 网络服务器上执行数学用户代码,最简单的安全方法是什么? [英] Executing mathematical user code on a python web server, what is the simplest secure way?

查看:57
本文介绍了在 python 网络服务器上执行数学用户代码,最简单的安全方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我意识到这个问题之前有人问过,但是这种情况略有不同.

I realise this question has been asked before, however this case is slightly different.

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

I want to run a python imageboard (using web.py), that will allow users to generate new images by submitting code. The code will be of the form of a single function that takes the x,y coordinates of a pixel and returns the r,g,b values, eg:

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

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

Only a very small syntax is required, and it doesn't necessarily have to be python. Using exec with limited scope seems to be too insecure, and using PyPy or a VM seems unnecessarily complex (I'm quite new to all this).

有没有一种 Pythonic 的方式来以更小的语言执行代码,而不是对其进行沙盒处理?要么是 Python 的一个子集(解析和白名单?),要么是一种我可以嵌入的面向数学的语言?

Rather than sandboxing it, is there a pythonic way to execute the code in a much smaller language? Either a subset of python (parsing and whitelisting?), or a math oriented language that I can embed?

推荐答案

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

This is the solution I went with. For a discussion of the security of this approach, see

感谢 arifwn,我开始探索 Python 的 ast(抽象语法树)模块.该模块提供了一个用于遍历树的类 ast.NodeVisitor.此代码子类 NodeVisitor 以创建语法检查器,将基本数学所需的代码列入白名单.函数调用和名称被特别监控,因为只允许某些函数,只允许未使用的名称.

Thanks to arifwn, I got into exploring Python's ast (abstract syntax tree) module. This module provides a class ast.NodeVisitor for traversing the tree. This code subclasses NodeVisitor to create a syntax checker that whitelists the code necessary for basic math. Function calls and names are specially monitored, as only certain functions should be allowed and only unused names should be permitted.

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

请注意,这旨在仅接受代码的数学部分,提供函数定义和返回语句.

Note that this is designed to accept only the mathematical part of the code, the function definition and return statement are provided.

这种将所有必需的安全构造列入白名单,特别是将所需的不安全构造列入白名单的方法,可以修改以生成许多有用的 Python 子集;非常适合用户脚本!

This method of whitelisting all the required safe constructs and specifically whitelisting required unsafe constructs, could be modified to produce many useful subsets of Python; excellent for user scripts!

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

Note that in order for this to be executed securely, it should be in it's own thread with a timeout, to reduce name collisions and time out if the user code generates an infinite loop or similar.

这篇关于在 python 网络服务器上执行数学用户代码,最简单的安全方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆