Python eval (kompilieren (…), Sandkasten), Globals gehen in Sandbox, wenn nicht in def, warum?

Folgendes berücksichtigen:

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 

Ich bin nicht einmal sicher, wie ich fragen soll, aber ich möchte den globalen Spielraum für eine Funktion, um die Umgebung zu sein, die ich beabsichtige, es auszuführen, ohne die Funktion während der Eval kompilieren zu müssen. Ist das möglich?

Danke für jede Eingabe

Lösung

 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 

    3 Solutions collect form web for “Python eval (kompilieren (…), Sandkasten), Globals gehen in Sandbox, wenn nicht in def, warum?”

    Wenn du eine Funktion in Python nennst, sind die globalen Variablen, die es sieht, immer die Globals des Moduls, in dem es definiert wurde. (Wenn dies nicht der Fall war, funktioniert die Funktion möglicherweise nicht – es könnte tatsächlich einige globale Werte benötigen und du Nicht unbedingt wissen, welche diese sind.) Das Angeben eines Wörterbuchs von globals mit exec oder eval() wirkt sich nur auf die globals aus, die der Code exec 'd oder eval() ' d sieht.

    Wenn du eine Funktion möchtest, um andere globals zu sehen, dann musst du ja tatsächlich die Funktionsdefinition in den String einfügen, den du an exec oder eval() . Wenn Sie dies tun, ist das "Modul" der Funktion der String, aus dem es zusammengestellt wurde, mit eigenen Globalen (dh denen, die Sie geliefert haben).

    Sie könnten dies func_globals , indem Sie eine neue Funktion mit dem gleichen Code-Objekt wie die, die Sie anrufen, aber ein anderes func_globals Attribut, das auf Ihre globals dict zeigt, aber das ist ziemlich fortgeschrittene hackery und wahrscheinlich nicht wert. Dennoch, hier ist, wie du es tun würdest:

     # 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 

    Externe Ausführungskontexte sind statisch in Python definiert ( f.func_globals ist schreibgeschützt), also würde ich sagen, dass das, was Sie wollen, nicht möglich ist. Der Grund ist, weil die Funktion ungültig werden könnte Python es seine Definition Kontext zur Laufzeit geändert wird. Wenn die Sprache es erlaubt hat, wäre es ein äußerst einfacher Weg zur Injektion von bösartigem Code in Bibliotheksanrufe.

     def mycheck(s): return True exec priviledged_code in {'check_password':mycheck} 

    Sandboxing Code für exec durch die Bereitstellung von alternativen globals / Einheimischen hat viele Einschränkungen:

    • Die alternativen globals / locals gelten nur für den code in the sandbox. Sie beeinflussen nichts außerhalb von ihr, sie können nichts außerhalb von ihr beeinflussen, und es wäre nicht sinnvoll, wenn sie könnten.

      Um es anders auszudrücken, übergibt dein sogenannter "Sandkasten" den Objekttest an den Code, der von exec ausgeführt wurde. Um die globals zu test die es testet, müsste es auch das Objekt modifizieren, es nicht so weitergeben, wie es ist. Das ist nicht wirklich möglich in irgendeiner Weise, die es funktionieren würde, viel weniger in einer Weise, dass das Objekt würde weiterhin etwas Sinnvolles tun.

    • Durch die Verwendung der alternativen Globalen würde alles in der sandbox noch die eingebauten sehen. Wenn du einige oder alle builtins aus dem Code in der Sandbox verstecken willst, musst du einen "__builtins__" Schlüssel zu deinem Wörterbuch hinzufügen, der auf entweder None (deaktiviert alle eingebauten) oder auf deine Version hinweist. Dies beschränkt auch bestimmte Attribute der Objekte, func_globals wird der Zugriff auf das func_globals Attribut einer Funktion deaktiviert.

    • Auch wenn Sie die builtins entfernen, ist die Sandbox immer noch nicht sicher. Sandbox nur Code, dass Sie auf den ersten Platz vertrauen.

    Hier ist ein einfacher Beweis des Konzepts:

     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) 
    Python ist die beste Programmiersprache der Welt.