warum subprocess.Popen() anstatt os.system()?

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.
Antworten
dirty sanchez
User
Beiträge: 42
Registriert: Freitag 27. Juni 2008, 12:21

Kann mir bitte jemand erklären warum man eine Shell vermeiden sollte, sprich subprocess.Popen() anstatt os.system() verwenden soll? Welche Gründe außer Quoting gibt es noch?
Ist rein interessehalber, hab aber nirgends was genaues und ausführliches gefunden. Schonmal im Voraus vielen Dank!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Neben dem angeführten Quoting sparst du dir auch noch den Aufruf einer zusätzlichen Shell die du gar nicht brauchst. Noch dazu bietet subprocess unter einem einheitlichen Interface eben alles mögliche was mit Kommunikation mit Prozessen nötig ist, statt es in os, os.popen* und popen2 zu verstreuen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und bei os.sytem soll man Schadcode einfügen können, was bei subprocess angeblich nicht möglich ist. Wie das genau funktioniert, habe ich allerdings auch noch nicht verstanden.
lunar

snafu hat geschrieben:Und bei os.sytem soll man Schadcode einfügen können, was bei subprocess angeblich nicht möglich ist. Wie das genau funktioniert, habe ich allerdings auch noch nicht verstanden.
So:

Code: Alles auswählen

$ ls this_will_be_removed                                                                                           
this_will_be_removed
$ cat less.py                                                                                                       
import os
import sys
os.system('less %s' % raw_input('filename: '))
$ python less.py                                                          
filename: less.py; rm this_will_be_removed
$ ls this_will_be_removed                                                                                           
ls: Zugriff auf this_will_be_removed nicht möglich: No such file or directory
os.system ist anfällig für Shell Injection durch Nutzereingabe. Im gezeigten Beispiel ist das noch nicht relevant (der Nutzer könnte rm ja auch direkt auf der Shell ausführen), wenn aber ein privilegierter Prozess derart unsicher mit Subprozessen umgeht, oder ein derartiges Snippet Dienst auf einem Webserver verrichtet, ist die Lücke immanent!

Man kann das über Whitelists, Blacklists oder Escaping verhindern, man kann aber auch einfach subprocess nutzen, was den Argumentvektor über "execlvp" direkt befüllt, und somit erst gar nicht anfällig dafür ist.

Außerdem ermöglicht das z.B. IFS-Angriffe: Bei manchen Unix-Shells wird $IFS bei der Shell-Initialisierung nicht initialisiert, sondern aus der Umgebung des Vater-Prozesses übernommen. Man kann also vor dem Kommando $IFS auf '/' setzen und exportieren, was dann dazu führt, dass dann der absolute Pfad des Kommandos geteilt wird, und der erste Bestandteil als im $PATH gesucht wird. Das wäre dann eine Art indirekter Shell Injection, die auch ohne Nutzereingabe funktioniert. Moderne Shells setzen $IFS aber zurück, so dass das unter Linux nicht mehr klappt.

Im Übrigen spart die Nutzung von "subprocess" auch einen fork/exec-Schritt, was der Performance nur zuträglich sein kann.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

lunar hat geschrieben: Man kann das über Whitelists, Blacklists oder Escaping verhindern, man kann aber auch einfach subprocess nutzen, was den Argumentvektor über "execlvp" direkt befüllt, und somit erst gar nicht anfällig dafür ist.
Schade, hättest du jetzt "... und somit erst gar keinen Angriffsvektor zulässt" geschrieben, hättest du einen Satz gehabt, mit dem du jeden Mathematiker in den Wahnsinn treiben kannst...
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
nummer9
User
Beiträge: 6
Registriert: Montag 23. Juni 2008, 12:19

Außerdem kann es vorkommen, dass der Benutzer z.B. eine exotische Shell hat oder gar keine und somit os.system nicht funktioniert. also ist es etwas systemabhängig.
lunar

nummer9 hat geschrieben:Außerdem kann es vorkommen, dass der Benutzer z.B. eine exotische Shell hat oder gar keine und somit os.system nicht funktioniert.
"system()" ist eine POSIX-Funktion, die immer die POSIX-Shell unter "/bin/sh" aufruft. Auf allen halbwegs POSIX-kompatiblen Systemen verhält sich "system()" immer gleich. Das betrifft eigentlich jedes Unix, und auch Linux.

Windows mit seinem Shell-Verschnitt tanzt natürlich aus der Reihe, aber im Unix-Universum ist "system()" plattformübergreifend.
Antworten