8

この質問は以前に行われたことがあると思いますが、この場合は少し異なります。

ユーザーがコードを送信することで新しい画像を生成できるようにする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を使用するのは不必要に複雑に思えます(私はこれらすべてにまったく慣れていません)。

サンドボックス化するのではなく、はるかに小さな言語でコードを実行するためのpythonicな方法はありますか?Pythonのサブセット(解析とホワイトリスト?)、または私が埋め込むことができる数学指向の言語のいずれか?

4

2 に答える 2

3

これは私が行った解決策です。このアプローチのセキュリティの説明については、を参照してください。

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

これはコードの数学的な部分のみを受け入れるように設計されており、関数定義とreturnステートメントが提供されていることに注意してください。

必要なすべての安全な構成をホワイトリストに登録し、特に必要な安全でない構成をホワイトリストに登録するこの方法は、Pythonの多くの有用なサブセットを生成するように変更できます。ユーザースクリプトに最適です!

これを安全に実行するには、名前の衝突を減らし、ユーザーコードが無限ループなどを生成した場合にタイムアウトするように、タイムアウト付きの独自のスレッドに含める必要があることに注意してください。

于 2012-05-18T14:15:43.657 に答える
1

pysandboxpypiページには多くのすばらしい情報があります。

于 2012-05-18T06:10:37.327 に答える