2010-12-29 5 views
4

は、次のことを考えてみましょう:Python eval(コンパイル(...)、サンドボックス)、グローバルではdefでない限りサンドボックスに入ります、なぜですか?

def test(s): 
    globals()['a'] = s 

sandbox = {'test': test} 
py_str = 'test("Setting A")\nglobals()["b"] = "Setting B"' 
eval(compile(py_str, '<string>', 'exec'), sandbox) 

'a' in sandbox # returns False, !What I dont want! 
'b' in sandbox # returns True, What I want 
'a' in globals() # returns True, !What I dont want! 
'b' in globals() # returns False, What I want 

私は聞いてどのようにしてもわからないんだけど、私は関数のグローバルスコープが中に機能をコンパイルすることなく、私はそれを実行する予定の環境になりたいですeval。これは可能ですか?任意の入力

ソリューション

def test(s): 
    globals()['a'] = s 

sandbox = {} 

# create a new version of test() that uses the sandbox for its globals 
newtest = type(test)(test.func_code, sandbox, test.func_name, test.func_defaults, 
        test.func_closure) 

# add the sandboxed version of test() to the sandbox 
sandbox["test"] = newtest 

py_str = 'test("Setting A")\nglobals()["b"] = "Setting B"' 
eval(compile(py_str, '<string>', 'exec'), sandbox) 

'a' in sandbox # returns True 
'b' in sandbox # returns True 
'a' in globals() # returns False 
'b' in globals() # returns False 
+0

何をしたい、とどのようにそれはクラスとメソッドを使用して異なっていますか? 'test'をクラスのメソッドにし、' self'という名前空間を使うようにします。どのようにこれはあなたのために働かないのですか? –

+0

私が探している唯一のことは、言語を深く研究する私の個人的関心から、Pythonの内部の仕組みに深く浸ることです。ほとんどのものと同様、この質問は実際の世界の問題に由来しますが、私はすでに解決しています。これは単に知識の追求です。 –

答えて

6

(これが本当でなかった場合は、機能が動作しない場合があります - 。それがかもしれない実際ににはのいくつかのグローバル値が必要ですが、必ずしもそのようなものはわかりません)execまたはeval()でグローバル辞書を指定すると、exec 'またはeval()'というコードが参照するグローバルにのみ影響します。

関数に他のグローバルを表示させる場合は、実際にはexecまたはeval()に渡す文字列に関数定義を含める必要があります。そうするとき、関数の "モジュール"はコンパイルされた文字列であり、独自のグローバル(つまり、あなたが提供したもの)である。

あなたは呼び出すコードオブジェクトと同じコードオブジェクトで新しい関数を作成することでこの問題を回避することができますが、グローバルのdictを指す別のfunc_globals属性がありますが、かなり進歩したハッカーであり、おそらく価値がありません。それでも、ここにあなたがそれを行うだろう方法は次のとおりです。代替グローバル/地元の人々を提供することにより、execため

# create a sandbox globals dict 
sandbox = {} 

# create a new version of test() that uses the sandbox for its globals 
newtest = type(test)(test.func_code, sandbox, test.func_name, test.func_defaults, 
        test.func_closure) 

# add the sandboxed version of test() to the sandbox 
sandbox["test"] = newtest 
+0

ありがとう、これは私がこのリンクを見つけたより多くの研究のための正しい方向で私を指すのに十分です。 http://code.activestate.com/recipes/577283-decorator-to-expose-local-variables-of-a-function-/ このリンクからもわかるように、「私はf.func_globalsをaカスタムディクショナリ[...]これはPythonインタープリタがPython呼び出しでfunc_globalsディクショナリを呼び出さず、PyDict_GetItemで直接呼び出すように機能しません。 " 私は疲れていて完全に理解できませんが、純粋なpythonでは不可能ですハッカー。私はバイトプレイで楽しくするつもりです。 ありがとうございます –

+0

サンドボックスを表示する関数の新しいバージョンを作成する例を追加しました。 – kindall

+0

非常にクールな、私は型オブジェクトがそれのような呼び出し可能だったのか分からなかった、pythonのdocsは特に、それが注意をリダイレクトするようなことをヒント、クラスのコンストラクタとしてそれを使用すること。 –

2

外部実行コンテキストは、Pythonで静的に定義されているため

おかげ(f.func_globalsは読み取り専用である)ので、私は何をしたいが不可能であると言うでしょう。その理由は、関数が無効なPythonになる可能性があるためです。実行時に定義コンテキストが変更されるためです。言語が許可されていれば、ライブラリ呼び出しに悪質なコードを注入するための非常に簡単なルートになります。

あなたはPythonで関数を呼び出すときに、それは見ているグローバル変数は、常にそれがで定義されたモジュールのグローバル変数です
def mycheck(s): 
    return True 

exec priviledged_code in {'check_password':mycheck} 
2

サンドボックスのコードは警告がたくさんあります。

  • 代替グローバル/地元の人々は唯一のコードに適用されますサンドボックス彼らはそれ以外のものには何の影響も及ぼさず、それ以外のものには影響を及ぼし得ません。

    別の言い方をすれば、いわゆる "サンドボックス"はオブジェクトtestをexecによって実行されたコードに渡します。 testが参照するグローバルを変更するには、オブジェクトをそのまま変更する必要があります。オブジェクトが意味のあることを何度もやり続けるような形では、それを機能させることはそれほど難しくありません。

  • 代替グローバルを使用することにより、​​で何かはまだ組み込みコマンドを参照してくださいます。あなたはサンドボックス内のコードから一部またはすべての組み込みコマンドを非表示にしたい場合は、None(すべての組み込みコマンドが無効になります)のいずれかまたはそれらのバージョンを指すあなたの辞書に"__builtins__"キーを追加する必要があります。これはまた、オブジェクトの特定の属性を制限します。たとえば、関数の属性func_globalsにアクセスすることは無効になります。

  • 組み込み関数を削除しても、サンドボックスはまだでなく、は安全です。最初に信頼するサンドボックスコードのみです。

ここでは概念の簡単な証拠です:

import subprocess 
code = """[x for x in().__class__.__bases__[0].__subclasses__() 
      if x.__name__ == 'Popen'][0](['ls', '-la']).wait()""" 
# The following runs "ls"... 
exec code in dict(__builtins__=None) 
# ...even though the following raises 
exec "(lambda:None).func_globals" in dict(__builtins__=None) 
+1

これは参考になりますが、手元のトピックは扱いません。私はevalの警告/不安について教訓を必要としていませんでした。このトピックをカバーするstackoverflowには、既にたくさんの他の質問があります。 –

関連する問題