わかった。私は専門家が話したのを知っ ています、そしてあなたは決して信頼できないデータにPythonを使うべきではありません。私は他の世界より頭が良くないので、これを試してはいけません。だが!とにかく行きます。 eval()
私の基本的な問題は、Pythonの構文のサブセットを使用して、信頼できない入力を受け取る小さな計算機評価プログラムを作成しようとしていることです。私は知っています:plyまたはpyparsingを使用して、パーサーを作成します。グローバル変数とローカル変数を渡すことで失敗してeval()
も、うまくいきません。
私が見た(そして心配していた)すべてのアプローチは、悪を列挙しようとします。ここでは、適切なものを列挙しようとしています。ASTを取得し、いくつかのノードタイプのみを許可してから、ホワイトリストに登録された関数のセットの1つに対する呼び出しであることを確認します。これがミニ実装(および要点)です:
import ast
import math
SAFE_FX = {
'exp': math.exp,
}
SAFE_NODES = set(
(ast.Expression,
ast.Num,
ast.Call,
ast.Name,
ast.Load,
ast.BinOp,
ast.Add,
ast.Sub,
ast.Mult,
ast.Div,)
)
class CleansingNodeVisitor(ast.NodeVisitor):
def generic_visit(self, node):
if type(node) not in SAFE_NODES:
raise Exception("%s not in SAFE_NODES" % type(node))
super(CleansingNodeVisitor, self).generic_visit(node)
def visit_Call(self, call):
if call.func.id not in SAFE_FX:
raise Exception("Unknown function: %s" % call.func.id)
def my_safe_eval(s):
tree = ast.parse(s, mode='eval')
cnv = CleansingNodeVisitor()
cnv.visit(tree)
compiled = compile(tree, s, "eval")
return(eval(compiled, SAFE_FX))
だから、トリックしmy_safe_eval('2*(4+exp(1.3))')
ながらも機能し、同様に禁止されています-禁止などなしで。my_safe_eval('[].__class__')
my_safe_eval('open("/something/evil")')
__builtins__
__locals__
私は...これはうまくいくと思います。私は怒っていますか?