Esta es la solución que fui. Para una discusión sobre la seguridad de este enfoque, ver
Gracias a arifwn, llegué a explorar ast
módulo de Python (árbol de sintaxis abstracta). Este módulo proporciona una clase ast.NodeVisitor
para atravesar el árbol. Este código crea subclases NodeVisitor
para crear un corrector de sintaxis que incluye el código necesario para matemáticas básicas. Las llamadas a funciones y los nombres se supervisan especialmente, ya que solo se deben permitir ciertas funciones y solo deben permitirse los nombres no utilizados.
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
Tenga en cuenta que esto está diseñado para aceptar sólo la parte matemática del código, se proporcionan la definición de la función y la instrucción de retorno.
Este método de incluir en una lista blanca todas las construcciones seguras requeridas y específicamente las listas blancas requeridas construcciones inseguras, podría modificarse para producir muchos subconjuntos útiles de Python; ¡Excelente para guiones de usuario!
Tenga en cuenta que para que esto se ejecute de forma segura, debe estar en su propio hilo con un tiempo de espera, para reducir colisiones de nombres y tiempo de espera si el código de usuario genera un bucle infinito o similar.
En realidad usaría un sandbox PyPy. –
Varias otras respuestas que leí votaron en contra ... Así que realmente no he investigado PyPy. Lo comprobaré gracias – SudoNhim
Una gran pregunta, quizás PyPy es la respuesta. Estaba hablando hoy sobre cómo Python podría ser un poco 'corto aquí, en comparación con decir lua. –