Skip to main content

Command Injection in Python: Beispiele und Prävention

Artikel von
Headshot of Rubaiat Hossain

Rubaiat Hossain

feature python command injection

21. Dezember 2023

0 Min. Lesezeit

Obwohl Python für seine Einfachheit und Vielseitigkeit bekannt ist, kann es schwierig sein, Python-Programme sicher zu halten, wenn Sie oder andere Teammitglieder während der Entwicklung Sicherheits-Best Practices vernachlässigen.

Außerdem verwenden Sie beim Entwickeln einer Python-Anwendung wahrscheinlich Bibliotheken oder andere Open-Source-Projekte. Diese Ressourcen können jedoch zusätzliche Sicherheitsprobleme verursachen, durch die Ihr Programm für Exploits wie Command Injection anfällig wird. Diese kritische Sicherheitslücke kann für Ihre Python-Anwendungen verheerende Folgen haben. Durch Command Injection können Angreifer in Ihren Anwendungen unbefugt Befehle ausführen, was zu Datenschutzverletzungen, einer Kompromittierung des Systems und anderen böswilligen Aktivitäten führen kann.

In diesem Artikel erfahren Sie alles über Command Injection und darüber, wie sich diese Schwachstelle in Ihren Programmen äußern kann. Außerdem lernen Sie gängige Sicherheits-Best Practices kennen, mit denen Sie Ihre Python-Apps vor Command-Injection-Angriffen schützen.

Was ist Command Injection?

Bei einer Command Injection kann ein Angreifer beliebige Systembefehle ausführen, indem er sie in ein anfälliges Programm einschleust. Die Schwachstelle entsteht in der Regel, wenn eine Anwendung nicht vertrauenswürdige Nutzerdaten (z. B. aus Formularen, Cookies und HTTP-Headern) an eine System-Shell übergibt.

Verschiedene Szenarien können zu Command-Injection-Schwachstellen führen, etwa wenn ungeprüfte Nutzereingaben an Systembefehle übergeben werden. Angreifer können schädliche Argumente einschleusen, wenn eine Anwendung Nutzereingaben direkt an die Befehlszeile übergibt. Ein Beispiel dafür ist die Command-Injection-Schwachstelle in bestimmten Versionen von MLflow (einer Plattform für den Lebenszyklus von Machine Learning). Ursache dieser Schwachstelle sind unzureichende Prüfungen der Methode predict() in der Datei backend.py.

Außerdem können Anwendungen Befehlszeichenfolgen dynamisch anhand verschiedener Parameter, darunter auch Nutzereingaben, zusammensetzen. Fehlen bei diesem Vorgang angemessene Prüfungen und Validierungen, lassen sich diese Befehle ausnutzen.

Leider werden die Auswirkungen von Systembefehlen leicht missverstanden. Der falsche Einsatz oder die fehlerhafte Konfiguration von Systembefehlen kann schnell zu Command-Injection-Schwachstellen führen. So sind beispielsweise betroffene Versionen von PaddlePaddle, einer Plattform für paralleles, verteiltes Deep Learning, über die Methode os.system in fs.py anfällig für Command Injection.

Die Folgen von Command Injection sind schwerwiegend. Angreifer können sich unbefugten Zugriff verschaffen, sensible Daten entwenden oder das System beschädigen. Solche Sicherheitsverletzungen können für Unternehmen finanzielle Verluste, einen Reputationsschaden und rechtliche Konsequenzen nach sich ziehen. Auch Nutzern, deren vertrauliche Informationen gestohlen werden, kann erheblicher Schaden entstehen.

Command Injection in Python verstehen und beheben

Command Injection zählt weiterhin zu den schwerwiegendsten Bedrohungen für die Anwendungssicherheit. Um Python-Anwendungen vor Command Injection zu schützen, müssen Sie diese Schwachstellen genau verstehen und proaktive Maßnahmen ergreifen, um potenzielle Exploits abzuwehren.

Häufige Schwachstellen, die zu Command Injection führen

Im folgenden Abschnitt werden einige häufige Schwachstellen beschrieben, die in Python zu Command Injection führen.

Vom Nutzer kontrollierte Eingaben ausnutzen

Vom Nutzer kontrollierte Eingaben sind Daten oder Werte, die Nutzer direkt bereitstellen, etwa Formulardaten, URL-Parameter oder Eingaben über die Befehlszeile. Verarbeitet eine Anwendung solche Eingaben ohne angemessene Validierung und verwendet sie direkt zur Ausführung von Systembefehlen, ist sie anfällig für Command-Injection-Angriffe.

Sehen Sie sich dazu dieses Python-Beispiel an:

# Vulnerability: Directly using user-controlled input to execute a command.
command = input("Enter a command to execute: ")
os.system(command)

Dieser Code fordert den Nutzer über die input-Methode zur Eingabe eines Befehls auf. Die so vom Nutzer kontrollierte Eingabe wird anschließend ohne Validierung oder Prüfung direkt an die Methode os.system zur Ausführung übergeben. Die Nutzereingabe wird also unmittelbar vom Befehlsinterpreter des Systems verarbeitet und ausgeführt:

Ubuntu-Terminal mit einem Python-Befehlseinschleusungstest, der einen bösartigen Befehl und eine Verzeichnisauflistung zeigt

In diesem einfachen Beispiel werden grundlegende Shell-Befehle verwendet, um den Code zu testen. Angreifer würden jedoch wahrscheinlich gefährliche Befehle einsetzen, die eine Rechteausweitung, Datenverlust und andere unerwünschte Folgen verursachen.

Unsichere Verwendung von Systembefehlen und des subprocess-Moduls

Systembefehle und das subprocess-Modul in Python ermöglichen die Ausführung von Shell-Befehlen und bieten leistungsstarke Möglichkeiten zur Interaktion mit dem zugrunde liegenden Betriebssystem. Bei unsachgemäßer Verwendung können sie jedoch Command-Injection-Schwachstellen verursachen, insbesondere in Verbindung mit vom Nutzer kontrollierten Eingaben.

Sehen Sie sich zur Veranschaulichung diese Schwachstelle an:

# Vulnerability: Using subprocess with shell=True and unsanitized user input.
command = input("Enter a command for subprocess: ")
subprocess.run(command, shell=True)

Hier werden Nutzereingaben direkt mit der Methode subprocess.run ausgeführt, wobei shell=True aktiviert ist. Das Argument shell=True bedeutet, dass die System-Shell den Befehl ausführt. Dadurch sind das Verketten von Befehlen und andere potenziell schädliche Aktionen möglich:

Ubuntu-Terminal, das eine Command-Injection in Python demonstriert, indem es die Befehle echo und ls ausführt.

Da die Nutzereingabe weder validiert noch bereinigt wird, ist das Skript Command-Injection-Angriffen ausgesetzt. Potenziellen Angreifern wird damit im Grunde die Kontrolle über die System-Shell überlassen.

Risiken durch dynamische Befehlserstellung

Python-Programme erstellen und führen häufig dynamisch Systembefehle aus, insbesondere wenn variable Daten wie Nutzereingaben eingebunden werden müssen. Fehlen bei dieser dynamischen Erstellung jedoch angemessene Sicherheitsmaßnahmen, entstehen dadurch Command-Injection-Schwachstellen.

Sehen Sie sich das folgende Python-Codebeispiel an:

# Vulnerability: Dynamically constructing commands without sanity checks.
user_input = input("Enter a parameter: ")
command = f"echo Printing {user_input}"
os.system(command)

Dieser Code fordert den Nutzer zur Eingabe eines Parameters auf und erstellt anschließend eine Befehlszeichenfolge, in die diese Eingabe direkt übernommen wird. Der Befehl soll die Nutzereingabe ausgeben. Da die Eingabe jedoch vor ihrer Einbindung in den Befehl weder validiert noch bereinigt wird, ist der Code anfällig für Command Injection:

Ubuntu-Terminal mit einer Python-Demo, die „Hello; ls -l“ empfängt und „Hello“ gefolgt von einer Verzeichnisliste ausgibt.

Ein Angreifer kann diese Schwachstelle ausnutzen, indem er eine Nutzlast mit Befehlstrennern oder Steueroperatoren eingibt. Ein Nutzer könnte beispielsweise Hello; ls -l eingeben. Dadurch würde zuerst "Hello" ausgegeben und anschließend aufgrund des Semikolons als Befehlstrenner der Inhalt des aktuellen Verzeichnisses aufgelistet. Das ist ein einfaches Beispiel, doch Angreifer können auch schädlichere Befehle eingeben, etwa rm -rf / oder cat /etc/shadow.

Unsichere Verwendung von eval()

Die Python-Funktion eval() wertet eine Zeichenfolge dynamisch als Python-Ausdruck aus und gibt das Ergebnis zurück. Sie ist zwar ein leistungsstarkes Werkzeug, kann aber auch erhebliche Risiken mit sich bringen. Sehen Sie sich das folgende Python-Codebeispiel an:

# Vulnerability: Insecure use of the eval() method.
user_input = input("Enter a Python expression to evaluate: ")
try:
    result = eval(user_input)
    print(f"Result:\n{result}")
except Exception as e:
    print(f"Error:\n{e}")

Die Verwendung von eval() in diesem Code ist gefährlich, da die Funktion nicht nur mathematische oder einfache Python-Ausdrücke, sondern beliebigen Python-Code auswertet. Hinzu kommt, dass Python über Module wie os mit dem zugrunde liegenden System interagieren kann.

Ein Angreifer kann beispielsweise Folgendes eingeben:

__import__('os').popen('ls').read()

Die obige Beispieleingabe importiert das Modul os und führt anschließend auf Unix-basierten Systemen den Befehl ls aus, der den Verzeichnisinhalt auflistet. Das ist eine einfache Demonstration. Böswillige Akteure können jedoch schädlichere Befehle eingeben, um Dateien zu manipulieren, Daten zu entwenden oder sich sogar unbefugten Zugriff auf das System zu verschaffen:

Terminal mit ausgeführtem demo.py und einem Python-Ausdruck, der os.popen('ls').read() verwendet und den Verzeichnisinhalt anzeigt.

Command-Injection-Schwachstellen entschärfen

Angesichts der potenziell schwerwiegenden Auswirkungen von Command Injection auf Ihre Python-Anwendungen ist es entscheidend, dieses Problem wirksam anzugehen. Glücklicherweise können Sie zahlreiche Command-Injection-Schwachstellen früh im Softwareentwicklungszyklus (SDLC) proaktiv entschärfen, indem Sie die folgenden Richtlinien befolgen.

Eingaben angemessen validieren und bereinigen

Eingaben von Nutzern oder externen Quellen dürfen niemals als vertrauenswürdig gelten. Validieren Sie Eingaben stets anhand erwarteter Muster und bereinigen Sie sie:

import re

def sanitize_input(user_input):
    # A simple example: Allow only alphanumeric characters
    return re.sub(r'[^a-zA-Z0-9]', '', user_input)

Beachten Sie, dass das obige Beispiel lediglich nicht alphanumerische Zeichen aus der Eingabe entfernt. Dadurch wird zwar verhindert, dass Angreifer Befehle verketten können, in einer echten Anwendung benötigen Sie jedoch wahrscheinlich deutlich strengere Bereinigungsregeln, zum Beispiel die Zulassung nur bestimmter bekannter Antworten.

Parametrisierte Abfragen und vorbereitete Anweisungen verwenden

Bei einer parametrisierten Abfrage wird ein Befehl zunächst mit seiner Struktur definiert. Anschließend werden die einzusetzenden Parameter separat übergeben. So werden Befehl und Daten niemals zu Zeichenfolgen verkettet. Stattdessen bleiben sie getrennt, und das System behandelt die Daten ausschließlich als Daten, nicht als ausführbaren Code.

Eine vorbereitete Anweisung geht noch einen Schritt weiter. Zunächst wird die Struktur des Befehls vorbereitet, anschließend werden nur noch die Parameter zum Ausfüllen der Platzhalter übergeben. Das subprocess-Modul von Python ermöglicht beispielsweise die Befehlsausführung, indem der Befehl von seinen Argumenten getrennt wird – ähnlich wie bei parametrisierten Abfragen:

import subprocess

command = "ls"
directory = input("Which directory to list? ")
subprocess.run([command, directory])

shell=True mit Vorsicht verwenden

Vermeiden Sie bei der Verwendung des subprocess-Moduls von Python das Argument shell=True, insbesondere bei Nutzereingaben. Wird ein Befehl mit shell=True ausgeführt, interpretiert die System-Shell jede übergebene Zeichenfolge. Enthält diese Zeichenfolge Nutzereingaben oder wurde sie ohne angemessene Bereinigung aus mehreren Quellen zusammengesetzt, kann ein Angreifer schädliche Befehle einschleusen:

command = input("Enter the directory to list: ")
subprocess.run(f"ls {command}", shell=True)

Das kann verheerende Folgen haben: unbefugter Systemzugriff, Datendiebstahl, die Installation von Malware, eine Rechteausweitung und die Ausführung beliebiger Befehle. Vermeiden Sie nach Möglichkeit shell=True oder bereinigen Sie zuerst die Eingabe, falls sich die Verwendung nicht vermeiden lässt.

Nutzereingaben nicht an os-Methoden übergeben

Wenn Sie Nutzereingaben direkt an os-Methoden wie os.spawn oder ähnliche übergeben, ist Ihre Python-Anwendung anfällig für Command Injection. Verwenden Sie deshalb alternative Python-APIs, sofern solche für Ihren Anwendungsfall verfügbar sind. Wenn Sie eine os-Methode benötigen, verwenden Sie sie möglichst ohne Nutzereingaben. Falls sich Nutzereingaben nicht vermeiden lassen, bereinigen Sie alle Eingaben und setzen Sie kontextbezogene Kodierungstechniken ein.

Berechtigungen beschränken und starke Zugriffskontrollen umsetzen

Führen Sie Ihre Anwendung immer mit den geringstmöglichen Berechtigungen aus. Wird eine Schwachstelle ausgenutzt, begrenzt dies den möglichen Schaden. Ziehen Sie außerdem in Betracht, Ihre Anwendung mithilfe von Tools oder Techniken wie chroot, Containern oder User-Namespaces zu isolieren.

Sichere Programmierkonventionen in Python

In den folgenden Abschnitten werden sichere Programmierkonventionen vorgestellt, die Ihre Python-Anwendungen bei korrekter Umsetzung vor Command-Injection-Schwachstellen schützen können.

Eingaben ordnungsgemäß validieren und bereinigen

Die Validierung und Bereinigung von Eingaben sind wesentliche Maßnahmen, um Ihre Python-Anwendungen vor Command Injection zu schützen. Indem Sie Nutzereingaben sorgfältig validieren und angemessen bereinigen, reduzieren Sie die Angriffsfläche, verhindern die unbefugte Ausführung von Befehlen und erhöhen die allgemeine Sicherheit Ihrer Software.

Sehen Sie sich den folgenden Code an:

def get_username():
    username = input("Enter your username: ")
    if len(username) < 3 or not username.isalnum():
        raise ValueError("Invalid username!")
    return username

Diese Funktion stellt vor der Verarbeitung sicher, dass die Eingabe eine festgelegte Länge hat und ausschließlich alphanumerische Zeichen enthält. Beachten Sie, dass Sie in einer realen Anwendung wahrscheinlich strengere Validierungsregeln benötigen als in diesem einfachen Beispiel.

Das subprocess-Modul und ähnliche Funktionen mit Bedacht verwenden

Das subprocess-Modul kann neue Prozesse starten, eine Verbindung zu deren Eingabe-, Ausgabe- und Fehlerdatenströmen herstellen und ihre Rückgabecodes abrufen. Daher muss dieses Modul unbedingt sicher verwendet werden.

Vermeiden Sie beim subprocess-Modul die Verwendung von shell=True, sofern sie nicht erforderlich ist. Andernfalls können Befehle in einer Shell ausgeführt werden, was Command-Injection-Angriffe ermöglicht:

# Avoid
subprocess.run("ls -l", shell=True)

# Instead Use
subprocess.run(["ls", "-l"])

Nutzereingaben und externe Befehle sicher verarbeiten

Verketten oder interpolieren Sie Nutzereingaben niemals direkt in Ihre Befehlszeichenfolgen. Verwenden Sie immer Argumentlisten:

user_input = input("Enter a directory name: ")

# Avoid
subprocess.run(f"ls {user_input}", shell=True)

# Prefer
subprocess.run(["ls", user_input])

Sicherheitsprobleme mit SAST- und SCA-Tools finden und beheben

Tools für statische Anwendungssicherheitstests (SAST) und Software Composition Analysis (SCA) helfen Ihnen dabei, sowohl Ihren eigenen Code als auch die Open-Source-Komponenten Ihrer Software zu analysieren und Schwachstellen früh im Entwicklungszyklus zu erkennen.

Die Snyk-Plattform macht das Auffinden und Beheben von Sicherheitsproblemen dank unseres hybriden KI-Ansatzes so einfach wie möglich. Dieser findet und behebt Schwachstellen in Ihrem Code und liefert Ihnen Echtzeit-Feedback zu potenziellen Sicherheitsrisiken sowie Empfehlungen zur Behebung. Mit SAST- und SCA-Tools wie Snyk (mit einem dauerhaft kostenlosen Tarif) können Sie Ihre Codebasis kontinuierlich auf Sicherheitsprobleme überwachen und diese frühzeitig beheben, bevor sie in die Produktion gelangen. So helfen wir Ihnen, Folgendes zu verhindern:

  • Kontakt mit schädlichen Paketen, die Ihr System oder Ihre Daten gefährden können

  • Angriffe auf die Software-Lieferkette, bei denen eine vertrauenswürdige Komponente kompromittiert wird und sich dies auf alle Softwareprodukte auswirkt, die von ihr abhängen

  • Veraltete Abhängigkeiten, die ungepatchte Schwachstellen enthalten können

Wenn Sie SAST- und SCA-Tools wie Snyk in Ihren Entwicklungsprozess integrieren, stellen Sie sicher, dass Sie nicht nur funktionsfähige Software entwickeln, sondern sie auch vor der sich ständig wandelnden Bedrohungslandschaft schützen.

Best Practices für die sichere Python-Entwicklung

In diesem Abschnitt lernen Sie grundlegende Programmiergewohnheiten und Workflows kennen, mit denen Sie eine sichere Python-Entwicklung teamübergreifend fördern können.

Regelmäßige Code-Reviews und Sicherheitsaudits durchführen

Regelmäßige Code-Reviews, bei denen Eingabevalidierung, Authentifizierungsmechanismen und der Umgang mit sensiblen Daten gründlich geprüft werden, helfen dabei, potenzielle Schwachstellen früh im Entwicklungszyklus zu erkennen. Wenn Sie Teammitglieder mit Sicherheitsexpertise einbeziehen, können Sie Probleme entdecken, die bei der ersten Entwicklung möglicherweise übersehen wurden, etwa unsichere Programmierpraktiken, fehlerhafte Konfigurationen und nicht bereinigte Eingaben.

Regelmäßige Sicherheitsaudits sind entscheidend, damit Ihre Codebasis auch angesichts neuer Bedrohungen robust bleibt. Mit Tools wie OpenVAS, ZAP und Metasploit können Sie Ihr Programm auf Schwachstellen testen.

Software und Bibliotheken auf dem neuesten Stand halten

Veraltete Software und Bibliotheken enthalten häufig bekannte Sicherheitslücken. Aktualisieren Sie Ihren Python-Interpreter, Ihre Frameworks und Drittanbieterbibliotheken kontinuierlich auf die neuesten Versionen. Nutzen Sie Paketmanager wie pip und Konfigurationsdateien wie requirements.txt, um Abhängigkeiten effizient zu verwalten und zu aktualisieren.

Sicherheitstools und Frameworks einsetzen

Sie können speziell für Python entwickelte Sicherheitstools und Frameworks nutzen, um die Erkennung von Schwachstellen zu automatisieren. Tools wie Snyk helfen dabei, Probleme auf Codeebene, fehlerhafte Sicherheitskonfigurationen und Schwachstellen in Paketen von Drittanbietern zu erkennen.

Python-Schwachstellen finden und beheben

Schützen Sie Ihre Anwendungen mit der Schwachstellensuche und den Behebungsempfehlungen von Snyk. 

Keine Kreditkarte erforderlich.

Oder registrieren Sie sich mit Azure AD Docker ID Bitbucket

Mit der Nutzung von Snyk erklären Sie sich mit unseren Richtlinien einverstanden, einschließlich unserer Nutzungsbedingungen und Datenschutzerklärung.

Eine sicherheitsorientierte Denkweise fördern

Es ist wichtig, bei Entwicklerinnen und Entwicklern ein Bewusstsein für Sicherheit zu fördern. Bieten Sie Schulungen, Workshops und Ressourcen zu Sicherheitsthemen an, um sie zu unterstützen. Wenn Sicherheit von Anfang an Priorität hat, verbessert sich die Qualität der gesamten Software und das Risiko von Schwachstellen sinkt.

Eine wertvolle Ressource, um mehr über den Aufbau einer sicherheitsorientierten Unternehmenskultur zu erfahren, ist der Secure Developer Podcast. Er enthält zahlreiche Interviews mit Sicherheitsverantwortlichen aus Unternehmen und geht ausführlich darauf ein, wie sie ihre Entwicklungsprogramme gestalten.

IDE-Erweiterungen zur Erkennung von Schwachstellen in Echtzeit sind wertvolle Tools, um anfälligen Code bereits beim Schreiben zu erkennen. Diese Erweiterungen sind direkt in Ihre Entwicklungsumgebung integriert und weisen Sie in Echtzeit auf potenzielle Sicherheitsprobleme hin:

Visual Studio Code zeigt Python-Code mit Snyk-Warnungen vor Command Injection durch nicht bereinigte Benutzereingaben.

Wenn Sie Schwachstellen bereits während der Entwicklung erkennen, sparen Sie Zeit und Aufwand, die Sie sonst später im Entwicklungszyklus investieren müssten – dann wäre ihre Behebung deutlich kostspieliger.

Fazit 

Command Injection ist ein schwerwiegendes Problem, das viele Python-Anwendungen betrifft. In diesem Leitfaden haben Sie erfahren, wie diese Schwachstelle auftreten kann und welche Risiken damit verbunden sind. Wenn Sie anfällige Code-Muster erkennen, gewinnen Sie wertvolle Einblicke in potenzielle Bedrohungen und die erforderlichen Gegenmaßnahmen.

Außerdem haben Sie sichere Programmierkonventionen kennengelernt, etwa die Validierung von Eingaben und den sorgfältigen Einsatz integrierter Systemmodule zum Ausführen von Befehlen. Mit diesen Strategien können Sie die Sicherheit Ihrer Python-Anwendungen stärken, potenzielle Angriffe abwehren und zur allgemeinen Widerstandsfähigkeit Ihrer Software beitragen.

Um Ihren Entwicklungsprozess weiter zu stärken, sollten Sie Tools wie Snyk nutzen. Die IDE-Erweiterungen von Snyk liefern Ihnen Echtzeit-Feedback zur Sicherheitk, scannen Ihren Code während des Schreibens und schlagen sofortige Korrekturen vor. Es ist, als würde Ihnen eine Sicherheitsexpertin oder ein Sicherheitsexperte über die Schulter schauen und dafür sorgen, dass Sie von Anfang an sicheren und robusten Code schreiben.

Sichern Sie Ihre Python-Apps ab

Finden und beheben Sie Python-Schwachstellen – kostenlos mit Snyk.

Keine Kreditkarte erforderlich.

Oder registrieren Sie sich mit Azure AD Docker ID Bitbucket

Mit der Nutzung von Snyk erklären Sie sich mit unseren Richtlinien einverstanden, einschließlich unserer Nutzungsbedingungen und Datenschutzerklärung.

Weiterlesen

Blog

Frontier-Modelle fanden die Schwachstellen. Nur der Angreifer fand die Angriffsketten.

Die statische Analyse fand die Schwachstellen, doch erst Live-Angriffstests bewiesen, wie sie sich zu Angriffen verketten lassen. Ein Vergleich von Evo COS, Claude Security und Claude Code Security.

feature insights context
Blog

Autonome Angriffe sind bereits Realität. Die Verteidigung muss Schritt halten.

Autonome Angreifer verkürzen das Zeitfenster für die Verteidigung. Erfahren Sie, wie kontinuierliches Erkennen, Beheben, Validieren und Verhindern Sicherheitsteams helfen kann, Schritt zu halten.

Blog

Warum KI-Coding-Agenten immer wieder fehlerhafte Zugriffskontrollen schreiben

KI-Coding-Agenten können Autorisierungslogik erzeugen, die kompiliert und die Prüfung besteht, dabei aber die Daten eines Mandanten für einen anderen offenlegt. Erfahren Sie, warum fehlerhafte Zugriffskontrollen schwer zu erkennen sind und wie Sie sie verhindern.