Sud*_*him 9 python security abstract-syntax-tree
原始问题:
在python Web服务器上执行数学用户代码,最简单的安全方法是什么?
由于需要Python的一小部分,我目前的方法是通过遍历Python的抽象语法树将允许的语法列入白名单.功能和名称得到特殊待遇; 只允许明确列入白名单的函数,并且只允许使用未使用的名称.
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.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
Run Code Online (Sandbox Code Playgroud)
这似乎接受了所需的语法,但我对编程很新,并且可能缺少任何数量巨大的安全漏洞.
所以我的问题是:这是否安全,是否有更好的方法,是否还有其他预防措施?
有两点我注意到你仍然可以改进:
您应该始终转义可以从某种形式的用户输入生成的任何输出.在您的示例中,不允许的标识符未经修改地镜像回输出.这可能被利用,例如Cross Site Scripting.因此,我还会逃避任何此类错误消息以防止这种情况.
您需要注意的另一件事是拒绝服务攻击.想象一下,有人掀起Ackermann函数和脚本向服务器提交了几千次......为了防止这种情况,你应该将所提交代码的执行时间设置为时间.这是必不可少的,因为这种类型的"攻击"经常无意中发生 - 有人设法产生无限循环.
编辑:
最后,我还建议更新您的Python版本以防止"hashDoS"攻击.
| 归档时间: |
|
| 查看次数: |
2333 次 |
| 最近记录: |