Python Sandboxing

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ja, ich weiß: Python Sandboxing (Sicheres Ausführen von Python Code aus unsicheren Quellen) ist mit CPython nicht wirklich möglich. Selbst, wenn man __buildins__ beschneidet und __include__ kontrolliert, kommt man mit diversen inspect-Tricks trotzdem an schädliche Module ran.

Aber, wenn ich

1) das Script in einer chroot Umgebung
2) als ein nicht-privilierter User
3) hinter einer Firewall

ausführe, sollte das Ganze doch einigermaßen sicher sein, oder? Was könnte ein böses Skript denn tun?

- Dateien auslesen oder überschreiben ist mit (1) geregelt. Es könnte sich höchstens selbst zerstören.
- Ausnutzen gefährliche System-Funktionen und das Binden von Netzwerk-Ports < 1024 ist dank (2) nicht mehr möglich.
- Alle anderen Netzwerk-Aktivitäten können durch (3) begrenzt werden.

Hab ich was übersehen?

PS: Es geht eigentlich darum: Ich bin am überlegen, einen Bottle-Hosting-Service auf zu bauen. Proof of concept und kostenloser Service, nichts kommerzielles. Dafür brauche ich aber eine sichere Möglichkeit, nicht vertrauenswürdige Scripte aus zu führen, ohne als Spam-Bot zu enden.
Bottle: Micro Web Framework + Development Blog
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Defnull hat geschrieben:1) das Script in einer chroot Umgebung
Also aus chroot kann man duchaus noch ausbrechen. An dieser Stelle würde ich persönlich echt überlegen ob man nicht FreeBSD Jails nutzen sollte. Zudem diese sowieso über bessere Restriktionsmöglichkeiten verfügen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

Nicht als unprivilegierter Nutzer. Solange man daran denkt, dass chroot nur das Dateisystem betrifft, kann man das durchaus sinnvoll nutzen.
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Ich hab vor, den Upload von beliebigen pure-python Modulen zu erlauben, führe den Python Interpreter und bottle.run() dann aber selbst aus. Meine Idee wäre:



1. Die User-Module und eine Kopie der Python Umgebung in ein neues Verzeichnis kopieren.
2. Das Verzeichnis komplett auf read only setzen.
3. Mit chroot in dieses Verzeichnis wechseln.
4. Ein ./var Verzeichnis mit schreib rechten und Dateisystem-Quota anlegen.
5. Mit "ulimit -m x -v x" den maximalen Ram-Verbrauch auf ein paar MB begrenzen.
6. Root-Rechte fallen lassen und zu einem umpriviligierten Benutzer wechseln.
7. Ein Python script starten, das ein bestimmtes User-Modul lädt und anschließend bottle.run() auf einem lokalen Port (1024+) startet. Dabei stdout und stderr in Log-Dateien in ./var umleiten.
8. Im Load Balancer eine neue subdomain an legen und auf den lokalen Port verweisen.
9. Regelmäßig prüfen, ob der Prozess noch läuft oder ein Modul veraltet ist und ihn gegebenenfalls neu starten.
10. Über ein Web Interface den inhalt von stdout und stderr zugänglich machen und dem User erlauben, den Prozess zu stoppen oder neu zu starten.
11. Regelmäßig prüfen, ob der Prozess weitere Prozesse gestartet oder weitere Ports belegt hat und dem Besitzer in den Arsch treten, sollte das der Fall sein.
12. Weitere Netzwerk-Verbindungen mit einer Firewall komplett verbieten.

Das Ganze könnte in etwa so aus sehen:

Code: Alles auswählen

domain=$1
port=$2
cp -a /opt/pydev/skel /opt/pydev/domains/$domain
cp -a /opt/pydev/userfiles/$domain/* /opt/pydev/domains/$domain/home/
cd /opt/pydev/domains/$domain
chmod -R a=rX .
chmod a=rx /bin/*
chmod a=rwX /var
ulimit -c0
ulimit -e20
ulimit -v$[16*1024] -m $[16*1024]
cd home
python /bin/start-app.py $port 1>/log/stdout 2>/log/stderr

Code: Alles auswählen

#!/bin/python
#/bin/start-app.py
import sys
import bottle
__import__('app')
bottle.start(server=bottle.Fapws3Server, host='localhost', port=int(sys.argv[2]))
Bottle: Micro Web Framework + Development Blog
Antworten