Questa è la soluzione con cui sono andato. Per una discussione sulla sicurezza di questo approccio, vedere
Grazie a arifwn, sono entrato in esplorare modulo di Python ast
(abstract albero di sintassi). Questo modulo fornisce una classe ast.NodeVisitor
per attraversare l'albero. Questo codice sottoclasse NodeVisitor
per creare un verificatore di sintassi che autorizzi il codice necessario per la matematica di base. Le chiamate e i nomi delle funzioni sono monitorati in modo specifico, poiché dovrebbero essere consentite solo alcune funzioni e dovrebbero essere consentiti solo nomi non utilizzati.
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
Si noti che questo è progettato per accettare solo la parte matematica del codice, la definizione della funzione e la dichiarazione di ritorno sono forniti.
Questo metodo di whitelisting tutti i costrutti sicuri necessari e in particolare la whitelisting richiedeva costrutti non sicuri, potrebbe essere modificato per produrre molti sottoinsiemi utili di Python; eccellente per gli script utente!
Si noti che per eseguire questo in modo sicuro, dovrebbe essere nella propria thread con un timeout, per ridurre il numero di collisioni e timeout se il codice utente genera un ciclo infinito o simile.
In realtà avrei usato una sandbox PyPy. –
Altre risposte che ho letto hanno votato contro ... Quindi non ho davvero guardato in PyPy - lo controllerò grazie – SudoNhim
Ottima domanda, forse PyPy è la risposta. Stavo parlando oggi di come Python potrebbe essere un po 'corto qui, rispetto a dire lua. –