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

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

Beitragvon dirty sanchez » Donnerstag 14. August 2008, 14:17

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!
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Donnerstag 14. August 2008, 15:23

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 Modvoice
Benutzeravatar
snafu
User
Beiträge: 5389
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Beitragvon snafu » Donnerstag 14. August 2008, 16:30

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

Beitragvon lunar » Donnerstag 14. August 2008, 19:03

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

Beitragvon birkenfeld » Donnerstag 14. August 2008, 20:56

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

Beitragvon nummer9 » Freitag 15. August 2008, 21:26

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

Beitragvon lunar » Samstag 16. August 2008, 08:43

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.

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]