これは私が行った解決策です。このアプローチのセキュリティの議論については、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の多くの有用なサブセットを生成するように変更できます。ユーザーのスクリプトに最適!
これが安全に実行されるためには、ユーザーコードが無限ループまたは同様のものを生成した場合に、名前の衝突を減らしタイムアウトするためにタイムアウト付きのスレッドが必要です。
私は実際にはPyPyサンドボックスを使用します。 –
私はそれに反対していくつかの他の答えを読んだ...だから私は実際にPyPyを見ていない - 私はそれをチェックしますよ – SudoNhim
素晴らしい質問、多分PyPyは答えです。今日、Pythonがルアと比べるとちょっと短いかもしれないことについて話していただけです。 –