Best Practices für die Ausführung von nicht vertrauenswürdigem Code

31

Ich habe ein Projekt, in dem ich Benutzern erlauben muss, beliebigen, nicht vertrauenswürdigen Python-Code ( ein bisschen wie diesen ) auf meinem Server auszuführen . Ich bin ziemlich neu in Python und möchte Fehler vermeiden, die Sicherheitslücken oder andere Schwachstellen in das System einführen. Gibt es Best Practices, empfohlene Lektüre oder andere Hinweise, die Sie mir geben können, um meinen Service nutzbar zu machen, aber nicht missbräuchlich?

Folgendes habe ich bisher in Betracht gezogen:

  • Entfernen Sie __builtins__aus dem execKontext, um die Verwendung von potenziell gefährlichen Paketen wie zu verbieten os. Benutzer können nur Pakete verwenden, die ich ihnen zur Verfügung stelle.
  • Verwenden Sie Threads, um eine angemessene Zeitüberschreitung zu erzwingen.
  • Ich möchte die Gesamtmenge an Speicher, die im execKontext zugewiesen werden kann, begrenzen , bin mir aber nicht sicher, ob dies überhaupt möglich ist.

Es gibt einige Alternativen zu einer Straße exec, aber ich bin mir nicht sicher, welche davon hier hilfreich wäre:

  • Verwenden von an ast.NodeVisitor, um jeden Versuch, auf unsichere Objekte zuzugreifen, abzufangen. Aber welche Gegenstände soll ich verbieten?
  • Suche nach doppelten Unterstrichen in der Eingabe. (weniger anmutig als die oben genannte Option).
  • Benutze PyPyoder ähnliches wie Sandbox den Code.

HINWEIS: Mir ist bekannt, dass es mindestens einen JavaScript-basierten Interpreter gibt. Das wird in meinem Szenario nicht funktionieren.

pswg
quelle
3
@ Martijn Pieters: Ausgezeichnet. Wahrscheinlich eine Antwort wert, wenn Sie jede einzelne zusammenfassen.
Robert Harvey
Bedenken Sie auch: auf der Festplatte verbleibender Müll, Netzwerk (Spam oder was auch immer darf nicht gesendet werden), Berechtigungen für andere Dateien (Lesen Ihrer Dateien). Sogar das Auswerfen einer while-Schleife kann die CD-Mechanik zerstören ... Ich würde mich für Virtualisierung (Jails oder ein paar KVMs, wie Sie es nennen) oder zumindest für Benutzer mit fast keinen Berechtigungen entscheiden. Stellen Sie einen angemessenen Wert und Speicherplatz ein, um Ihre eigenen Programme zu optimieren.
Kyticka
1
Versuchen Sie es mit PyPy :> Sandboxing: PyPy bietet die Möglichkeit, nicht vertrauenswürdigen Code vollständig sicher auszuführen.
Vorac,

Antworten:

28

Python Sandboxing ist schwer . Python ist von Natur aus auf mehreren Ebenen nachvollziehbar.

Dies bedeutet auch, dass Sie die Factory-Methoden für bestimmte Typen von diesen Typen selbst finden und neue Low-Level-Objekte erstellen können, die ohne Einschränkung direkt vom Interpreter ausgeführt werden.

Hier sind einige Beispiele für die Suche nach kreativen Möglichkeiten, um aus Python-Sandboxen auszubrechen:

Die Grundidee ist immer, einen Weg zu finden, um Basis-Python-Typen zu erstellen. Funktionen und Klassen und brechen Sie aus der Shell aus, indem Sie den Python-Interpreter veranlassen, beliebigen (ungeprüften!) Bytecode auszuführen.

Gleiches und mehr gilt für die execAnweisung ( exec()Funktion in Python 3).

Sie möchten also:

  • Kontrollieren Sie die Byte-Kompilierung des Python-Codes genau oder verarbeiten Sie den Byte-Code zumindest nach, um den Zugriff auf Namen zu verhindern, die mit Unterstrichen beginnen.

    Dies erfordert genaue Kenntnisse über die Funktionsweise des Python-Interpreters und die Struktur des Python-Bytecodes. Codeobjekte sind verschachtelt. Der Bytecode eines Moduls deckt nur die oberste Ebene von Anweisungen ab. Jede Funktion und Klasse besteht aus einer eigenen Bytecode-Sequenz sowie Metadaten, die beispielsweise andere Bytecode-Objekte für verschachtelte Funktionen und Klassen enthalten.

  • Sie müssen Module, die verwendet werden können, auf die Whitelist setzen . Vorsichtig.

    Ein Python-Modul enthält Verweise auf andere Module. Wenn Sie importieren os, enthält osIhr Modulnamensbereich einen lokalen Namen, der auf das Modul verweist os. Dies kann einen entschlossenen Angreifer zu Modulen führen, die ihm helfen können, aus der Sandbox auszubrechen. Mit dem pickleModul können Sie beispielsweise beliebige Codeobjekte laden. Wenn also ein Pfad durch auf der Whitelist befindliche Module zum pickleModul führt, haben Sie immer noch ein Problem.

  • Sie müssen die Zeitkontingente streng einschränken. Selbst der neutralste Code kann immer noch versuchen, für immer zu laufen und Ihre Ressourcen zu binden.

Schauen Sie sich RestrictedPython an , das versucht, Ihnen die strikte Bytecode-Kontrolle zu geben. RestrictedPythonwandelt Python-Code in etwas um, mit dem Sie steuern können, welche Namen, Module und Objekte in Python 2.3 bis 2.7 zulässig sind.

Ob dies RestrictedPythonfür Ihre Zwecke sicher genug ist, hängt von den von Ihnen implementierten Richtlinien ab. Das Nichtzulassen des Zugriffs auf Namen, die mit einem Unterstrich beginnen, und das strikte Whitelisten der Module wären ein Anfang.

Meiner Meinung nach ist die einzige wirklich robuste Option die Verwendung einer separaten virtuellen Maschine ohne Netzwerkzugriff auf die Außenwelt, die Sie nach jedem Durchlauf zerstören. Jedes neue Skript erhält stattdessen eine neue VM. Selbst wenn der Code aus Ihrer Python-Sandbox ausbricht (was nicht unwahrscheinlich ist), kann der Angreifer nur von kurzer Dauer und ohne Wert darauf zugreifen.

Martijn Pieters
quelle
10

TL; DR Verwenden Sie eine Chroot / Jail und führen Sie sie als benutzerdefinierter Benutzer ohne Berechtigungen aus.

Die beste Praxis nicht vertrauenswürdigen Code für die Ausführung ist es über ein abzusondern System Sandbox. Für die meiste Sicherheit:

  • Erstellen Sie einen Container mit nur Python und seinen Abhängigkeiten sowie den Abhängigkeiten des Containers
  • Erstellen Sie einen Container ohne alle Geräte, die nicht unbedingt erforderlich sind (z. B. Netzwerk und Speicher).
  • Erstellen Sie einen Container mit Einschränkungen für die Speicher- und Prozessnutzung
  • Erstellen Sie den Container bei jedem Durchlauf neu (oder zumindest bei jedem einzelnen Benutzer und maximalem Zeitraum).
  • Führen Sie das Programm als Benutzer mit den geringsten Berechtigungen aus
  • Als Benutzer ausführen, der nicht zum Schreiben von Dateien berechtigt ist

Sie befolgen auch die Standardverfahren zum sicheren Ausführen von Dingen in einer Chroot. Sie können das Dateisystem der Chroot auch bei jedem Aufruf neu erstellen, was besonders paranoid ist. Normalerweise können Benutzer das Dateisystem, in dem chroot ausgeführt wird, nicht ändern.

dietbuddha
quelle
Dies ist das einzige, bei dem Sie sich auch nur aus der Ferne sicher sein können, dass Sie es richtig gemacht haben - geben Sie ihm seinen eigenen Prozess.
Michael Kohne
3

Auf keinen Fall können Sie dies sicher tun.

Wenn Sie so etwas sicher tun möchten, müssen Sie zunächst eine eigene Implementierung von Python haben, die in einer vollständig kontrollierten Umgebung ausgeführt wird, vorzugsweise im Browser des Benutzers statt auf Ihrem System. Sie können mit Jython (Python für Java) beginnen und es als Java-Applet verpacken. Da es in der Java-Sandbox auf dem Computer des Benutzers ausgeführt wird, ist Ihr System relativ sicher.

ddyer
quelle
4
Die Frage der Sicherheit betraf seinen Server, nicht den Computer des Kunden. Die potenziellen Sicherheitsrisiken von Java wie bei jeder anderen Web-Technologie bestehen darin, dass der Server zum Bereitstellen von Programmen verwendet werden kann, die für den Client gefährlich sind.
Ddyer
1
@grasGendarme, ähnlich wie neue Geschichten über Flugzeugabstürze, erzählen Ihnen viel darüber, wie selten diese sind. Geschichten über Java-Sicherheitslücken erzählen Ihnen, dass Java vergleichsweise sicher ist. Du würdest niemals eine solche Geschichte über C bekommen, weil die Antwort wäre: "Nun, wenn du es ausführst, wird es tun, was es will"
Richard Tingle
2

Wie Martijn oben sagte, ist dies in Python wirklich sehr, sehr schwierig. Ich halte es nicht für möglich, die Sprachfunktionen einzuschränken, da Python so nachvollziehbar ist. Und wenn Sie eine Sandbox für eine Python-Version zum Laufen bringen, besteht die Möglichkeit, dass die nächste Version diese kaputt macht.

Ich würde mir PyPy anstelle von Standard-CPython ansehen . Kurz gesagt, es ist eine kompatible alternative Implementierung von Python. Es hat mehrere Vorteile und unterschiedliche Funktionen, und eine davon ist das Sandboxing durch Ersetzen von Systemaufrufen, anstatt die Sprachfunktionen einzuschränken.

James
quelle
0

Solange die Leistung für Sie nicht besonders wichtig ist, können Sie sie immer in Brython ausführen, wodurch sie effektiv in die JavaScript-Sandbox eingefügt wird

Big Ian
quelle