Wie kann ich die globals() kopieren?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Wie kann ich die globals kopieren, sodass sie auch funktionieren.

Ich möchte eine Kopie von den globals, um daraus sicherheitsrelevante builtin Funktionen, wie etwa import beseitigen zu können. Aber nicht mal Kopieren klappt:

Code: Alles auswählen

        my_dict = dict(globals())
        exec(evcode,my_dict,locals())
Mit copy funktioniert es auch nicht.

Ich würde gerne, weil sich builtin Funktionen nicht löschen lassen, mir herauskopieren was ich brauche, etwa:

Code: Alles auswählen

         for key,data in globals().items():
            if key != '__import__':
                s_dict[key]=data
Aber hinterher funktionieren die kopierten globals() anscheinend nicht richtig.
BlackJack

@Alfons Mittelmeyer: Vergiss es, Du bekommst den Python-Interpreter nicht mit einfachen Mitteln sicher. Der ist dafür einfach nicht ausgelegt, so etwas müsste man von Grund auf einplanen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sicher bekäme man ihn schon, so sicher, dass er nicht mal mehr print ausführen kann. Aber so sicher möchte ich ihn nicht haben, anderes sollte doch auch noch funktionieren.
BlackJack

@Alfons Mittelmeyer: Es gab mal den Versuch ihn sicher zu bekommen, das Modul ist aus der Standardbibliothek rausgeflogen weil es immer wieder Wege gab das auszuhebeln, ganz einfach weil Python von seiner Natur aus kein ”private” kennt und Introspection sehr einfach macht. Wenn die Python-Core-Entwickler das trotz fortgesetzter Bemühungen nicht schaffen, wirst Du das sicher auch nicht schaffen. Mal was ganz einfaches: ``python -c 'print object.__subclasses__()'``, da ist unter anderem `zipimport.zipimporter` mit in der Liste. Und das ist nur *ein* weg an andere Objekte heranzukommen die nicht direkt in `__builtins__` drin sind.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Was Du brauchst:

Code: Alles auswählen

chroot(Popen(['downstripped_python_interpreter', 'remote.py']))
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Zum einen gibt es die dict comprehension:

Code: Alles auswählen

foo = {k: v for k, v in globals().items() if k not in ['__import__']}
Beachten sollte man allerdings, dass hier flache Kopien (shallow copies) angelegt werden.

Zum anderen ist import ein statement und daher Sprachbestandteil, welchen man über diesen Weg nicht ausschließen kann.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Naja, etwas scheint python nicht von den globals kopieren zu wollen, nämlich keine tkinter widgets. Wieso eigentlich nicht?
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Code: Alles auswählen

>>> import tkinter as tk
>>> foo = {k: v for k, v in globals().items()}
>>> root = foo['tk'].Tk()
>>> frame = foo['tk'].Entry(root)
>>> frame.pack()
>>> root.mainloop()
Pas de problème.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Da ist zipimporter als type drin. Also kennt python auch einen type zipimport.zipimporter. Doch um ihn zu benützen, braucht es wohl:
import zipimport

Der . besagt dass es sich um ein Modul handelt und das muss man ja wohl erst importieren.
BlackJack

@Alfons Mittelmeyer: Nein, es braucht eben *keinen* Import, der Datentyp ist doch in der Liste enthalten. Da kann man ihn sich anhand des Namens rausfischen und dann benutzen.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Der Punkt besagt nicht mehr als dass es sich um einen Attributszugriff handelt. Um ein Modulobjekt zu bekommen braucht es eben _keinen_ Import. Das ist der ganze Punkt von BlackJacks Post: Die Moeglichkeit `import` loszuwerden bringt dir rein gar nichts.

Code: Alles auswählen

In [14]: [x for x in object.__subclasses__() if 'zipimporter' in x.__name__]
Out[14]: [zipimport.zipimporter]

In [15]: [x for x in object.__subclasses__() if 'zipimporter' in x.__name__][0]('foo.zip')
---------------------------------------------------------------------------
ZipImportError                            Traceback (most recent call last)
<ipython-input-15-821efb93d245> in <module>()
----> 1 [x for x in object.__subclasses__() if 'zipimporter' in x.__name__][0]('foo.zip')

ZipImportError: not a Zip file
Und wenn man jetzt noch ein Zip Modul an dem Pfad hat, dann hat man einen Import.
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: nochmal ein illustratives Beispiel. Du importierst irgendwo subprocess und gibst Deinem exec nur eine unschuldige Klasse und keine __builtins__:

Code: Alles auswählen

import subprocess
class Abc(object):
    pass
exec """
Popen = [cl for cl in Abc.__base__.__subclasses__() if cl.__name__=='Popen'][0]
Popen('ls').communicate()
""" in {'__builtins__': {}, 'Abc':Abc},{}
:twisted: :twisted: :twisted:
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Wir haben das doch schon zigmal durchgekaut - Du bekommst das mit Python innerhalb eines Interpreters nicht sicher, egal ob Du exec, import, weiss der Geier was.... mit Pythoncode nutzt. Geht nicht. Punkt. Egal welche Verrenkung Du anstellst - solange Du nicht den Interpreter selbst manipulierst, wird das nicht sicher. Egal wie wenig Du das hören möchtest, es wird nichts. Nein. Geht nicht.

Diese Diskussionen haben schon was von täglichen Murmeltieren.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Also das mit global ist wohl ein spezielles unidentifizierbares Problem. Es geht ewig gut und läuft da vielmals richtig durch, die GUI wird zum großen Teil aufgebaut, und dann findet das Programm etwas nicht. Wo es dann aussteigt, haben sowohl die globals() als auch die kopierten, jeweils 800 Zeilen. Ob da ein Unterschied ist, schwer zu sagen. Müßte man mit irgendeinem Programm alphabetisch sortieren, um es dann nebeneinander legen zu können.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Natürlich bekommt man Python nicht vollkommen sicher. Aber wenn man einfache Beispielprogramme für tkinter nach kritischen Stellen per Programm durchsucht, sie sich anschaut und begutachtet und zusätzlich bei den Nutzern Dinge wie import ausschaltet bei http:// sollte große Sicherheit bestehen.

Und so etwas, bei dem zipimport und __subclasses__ und dergleichen vorkommt - das kann man ja mit einem search feststellen, das lässt man nicht zu.

Wenn jemand Programme aus unsicheren Stellen einbindet, das kann er auch mit import tun, dagegen kann man nichts machen. Es geht hier nicht darum, dass man mit Python möglichst viel machen kann, sondern nur soviel, wie für tkinter Programmbeispiele nötig ist und da dürfte sich das Risiko auf Null reduzieren lassen, wenn auch die Programme nicht ohne Prüfung durchgelassen werden.

Was jemand allerdings selber programmiert und für sich nutzt, und was er da tut, das bleibt ihm selbstverstänldich selber überlassen.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Nach wie vielen Zeichenketten willst du denn suchen, um die zu verhindern?
Es gibt schlicht eine endlose Liste von Möglichkeiten, die du unmöglich überblicken kannst.

Hier haben dir schon eine Menge Leute gesagt, dass das was du tust nicht funktioniert. Du bist wieder der Geisterfahrer.

Und du machst dir Gedanken über Dinge, die von sehr vielen Leuten bereits beleuchtet wurden. Das ist Verschwendung.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ein Glueck, dass nur Zeichenketten problematisch sind! Offensichtlich unschuldig:

Code: Alles auswählen

reduce(lambda a, b: a + b, (chr(i) for i in [122, 105, 112, 105, 109, 112, 111, 114, 116, 101, 114]))

@sparrow: Nein, das kann nicht sein, schliesslich sieht er doch Hunderte von Geisterfahrern.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Alfons Mittelmeyer hat geschrieben:Und so etwas, bei dem zipimport und __subclasses__ und dergleichen vorkommt - das kann man ja mit einem search feststellen, das lässt man nicht zu.
Na dann, auf gehts:

Code: Alles auswählen

eval("[k sbe k va bowrpg.__fhopynffrf__() vs 'mvcvzcbegre' va k.__anzr__]".decode('rot13'))
Alfons Mittelmeyer hat geschrieben:... wie für tkinter Programmbeispiele nötig ist und da dürfte sich das Risiko auf Null reduzieren lassen ...
Dir ist doch sicherlich klar, dass tkinter intern einen Tcl-Interpreter hat, gelle? Dieser Interpreter ist im Übrigen auch für systemnahe Programmierung ausgelegt, nur halt nicht so verbreitet wie Python selbst. Der geneigte Alfons wird schon rausfinden, was das eigentlich in Bezug auf die Aussage bedeutet. Vielleicht.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Fehler gefunden: globale Variable

Das ist schon sehr alter Code. hatte gedacht, weil das ein Objekt wäre, wäre es keine Variable:

Code: Alles auswählen

_Selection=Create_Selection()
Ist aber nicht so. Diese Referenz ändere ich ständig. Wenn ich globals() kopiere bekomme ich den augenblicklichen Wert (Referenz auf ein Objekt).
Wenn dann _Selection aktualisiert wird (neue Referenz), dann nicht in der Kopie der globals().

Eine Funktion dagegen hilft:

Code: Alles auswählen

def _get_selection(): return _Selection
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

PyPy hat Sandboxing was tatsächlich funktioniert und sicher ist. Der Code dem man nicht vertraut wird allerdings auch in einem anderen Prozess ausgeführt und man muss dann mit dem irgendwie kommunizieren und sicherstellen dass man dabei nicht selbst wieder Sicherheitslücken einführt.
Antworten