2012-05-18 35 views
7

我意識到這個問題之前已經被問過,但是這個案例有些不同。在python Web服務器上執行數學用戶代碼,最簡單的安全方式是什麼?

我想運行一個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或虛擬機似乎不必要的複雜(我對這一切都很陌生)。

而不是沙箱,是否有python的方式來執行一個更小的語言的代碼?要麼是Python的一個子集(解析和白名單?),還是我可以嵌入的數學導向語言?

+2

我實際上會使用PyPy沙箱。 –

+0

我讀過的其他幾個答案反對它......所以我沒有真正看過PyPy - 我會檢查出來的,謝謝 – SudoNhim

+0

好的問題,也許PyPy是答案。今天只是在談論有關Python如何可能在這裏短缺,相比之下,說lua。 –

回答

2

這是我一起去的解決方案。對於這種方法的安全性的討論,請參見

感謝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 

請注意,這被設計爲只接受代碼的數學部分,函數定義和返回語句提供。

這種將所有必需的安全結構白名單列入白名單所需的不安全結構的方法可以修改,以產生許多有用的Python子集;非常適合用戶腳本!

請注意,爲了安全地執行此操作,它應該在它自己的線程中超時,以減少名稱衝突並在用戶代碼生成無限循環或類似代碼時超時。

+0

這應該是IMO的獨立問題。 – TryPyPy

+0

對不起。我知道有人能夠希望爲我檢查它;如果他發現它可以,我會重新格式化它更像是一個答案。 (否則我會刪除它)。 – SudoNhim

+0

我的意思是:如果你將這個答案轉換成新的問題,你會得到更多的眼睛(也可能是新的建議):) – TryPyPy

相關問題