Flavijus Piliponis â stock.ado
Risiken der Python-Anweisung import und wie man sich schützt
Die Python-Anweisung import birgt ein Sicherheitsrisiko, auf das Entwickler achten müssen. Hier erfahren Sie, wie sie funktioniert und warum es keine einfache Lösung gibt.
Bei der Verwendung von Python gibt es eine Gefahr, auf die Sie vorbereitet sein müssen. Alle modernen Programmiersprachen sind modular aufgebaut, das heißt Entwickler können größere Codeabschnitte in kleinere, besser handhabbare Bestandteile zerlegen. Dadurch können sie Codeeinheiten wiederverwenden, die normalerweise in Bibliotheken zusammengefasst sind. Diese Bibliotheken werden oft nicht selbst geschrieben, sondern sind Open-Source-Sammlungen, die für gängige Aufgaben wie Datenbankanbindung oder Array-Berechnungen erstellt wurden.
Damit Codeeinheiten mit den Methoden und Eigenschaften anderer Codeeinheiten arbeiten können, müssen sie auf diese Komponenten verweisen. Moderne Sprachen, darunter Java und Python, setzen diese Anforderung in Form einer import-Anweisung um. Diese bildet das Rückgrat des gesamten modernen Unternehmenscodes.
In Python birgt die Verwendung der import-Anweisung jedoch eine Gefahr. Lassen Sie uns untersuchen, warum das so ist, und wie man das Problem in den Griff bekommt.
Was ist das Problem bei Python?
In den meisten modernen Sprachen müssen Sie, um eine Datei zu importieren, entweder eine Instanz der zu verwendenden Bibliothek erstellen oder eine statische Methode direkt aufrufen. In beiden Fällen müssen Sie etwas im Code tun, um etwas innerhalb des Imports auszuführen.
Python ist eine Ausnahme. Wenn Sie eine Datei mit Python importieren, wird jeder Top-Level-Code, der keine Methode ist, sofort ausgeführt.
Viele Entwickler nutzen diese Importfunktion von Python zu ihrem Vorteil. Sie schreiben zum Beispiel Code in den Top-Level Body einer Python-Datei, um ihren Code zu testen oder um Annahmen zu überprüfen, die die Bibliothek für Abhängigkeiten macht.
Python ist im Grunde eine Skriptsprache, und die Möglichkeit, Logik direkt aus dem Body einer Datei zu schreiben und auszuführen, ist eine überzeugende Funktion. Allerdings führt dieselbe Funktion naturgemäß auch Code aus, wenn nichts explizit zur Ausführung aufgerufen wurde – und das ist potenziell ein großes Problem.
Worin besteht die Gefahr bei Python?
Die Fähigkeit von Python, Code beim Importieren auszuführen, hat drei Risikoebenen für ein Unternehmen: versehentliches Risiko, absichtliches Risiko und externes Risiko.
Ein versehentliches Risiko besteht, wenn ein Entwickler Code zum Top-Level Body eines Imports hinzufügt oder an ihm ändert, möglicherweise, um etwas zu testen, und vergisst, diesen speziellen Code wieder zu entfernen, nachdem er fertig ist. Dies kann unnötige Ressourcen verbrauchen, Protokolldateien mit unsinnigen Fehlermeldungen füllen oder Tests ausführen, die Endlosschleifen oder ähnliche Probleme enthalten. Diese Probleme sind schwer aufzuspüren, da der Code selbst nirgendwo explizit aufgerufen wird.
Ein absichtliches Risiko liegt vor, wenn ein Entwickler einen Top-Level Body eines Imports in böswilliger Absicht verändert. Auf diese Weise kann er zum Beispiel Kryptomining-Routinen ausführen, vertrauliche Informationen aus dem Netzwerk exportieren, einen Backdoor-Trojaner im Netzwerk installieren oder einfach den Code an einer absichtlich schwer zu findenden Stelle zum Absturz bringen.
Das externe Risiko ist vielleicht das heimtückischste Risiko. Hier macht keiner der Entwickler etwas falsch, weder aus Versehen noch aus anderen Gründen. Stattdessen gelingt es einer böswilligen dritten Partei, eine externe Bibliothek zu kompromittieren, die das Unternehmen verwendet. Böswillige Akteure könnten dann Hintertüren im Netzwerk des Unternehmens installieren, um Daten zu kompromittieren, Kryptowährung zu schürfen oder einen Ransomware-Angriff zu starten.
Solche kompromittierten Bibliotheken werden zunehmend als Angriffsvektor gegen Unternehmen eingesetzt. In anderen Sprachen als Python sind sie immer noch darauf angewiesen, dass Code ausgeführt wird, damit sie überhaupt funktionieren. In Python brauchen sie nur eine import-Anweisung.
Wie löst Python dieses Problem?
Um dieses Problem zu lösen, verlangt Python, dass jeder Code, den ein Entwickler ausführen möchte, in einem speziellen Abschnitt des Codes enthalten ist, der nur ausgeführt wird, wenn die Datei als Anwendung ausgeführt wird, und nicht erst beim Import.
Dies wird durch eine if-Anweisung implementiert, die überprüft, ob __name__ __main__ ist. Hier ist ein einfaches Beispiel, wie das funktioniert:
def some_method():
return "Hello, world!"
print("Dies wird immer angezeigt")
if __name__ == "__main__":
print("Dies wird nur angezeigt, wenn es direkt ausgeführt wird")
Wenn die Datei importiert wurde, wird ausgegeben: „Dies wird immer angezeigt.“ Wenn sie direkt ausgeführt wird, wird „Dies wird immer angezeigt“ und außerdem „Dies wird nur angezeigt, wenn dies direkt ausgeführt wird.“
Das Problem bei diesem Ansatz ist, dass er vollständig von der Ehrlichkeit der Entwickler abhängt. In einer normalen Entwicklungsumgebung funktioniert er gut genug, und die einzige Sorge sind Unfälle. Es bietet aber keinerlei Schutz vor böswilligen Akteuren, egal ob extern oder intern.
Warum ist dies in anderen Sprachen kein Problem?
Andere moderne Sprachen, wie Java oder C#, führen beim Importieren niemals automatisch Code aus. Ein Entwickler muss entweder eine Klasse über den Import initialisieren oder eine statische Methode innerhalb des Imports aufrufen. Dies erhöht die Hürde für bösartigen Code, der das System ausnutzen kann, erheblich.
Ist das Problem überbewertet?
Die Schwere des Problems hängt weitgehend von den internen Praktiken eines Unternehmens ab, zum Beispiel von Unit-Tests und der Quellcodekontrolle. Leider helfen solche Standardverfahren wenig, um einen böswilligen Akteur einzudämmen.
Betrachten Sie eine einfache Payload, die eine Shell öffnet und eine Verbindung zu einem Port herstellt, der Fernzugriff erlaubt. Anschließend findet die Payload einen Second-Level-Import und fügt den Code am Ende der Datei ein. Oder, noch besser, sie platziert den Code zwischen Methoden.
Das ist alles, was es braucht, um das Problem der Python-Importanweisungen auszunutzen.
Der Code ist in dem Fall wenig umfangreich und beansprucht nur minimale Ressourcen. Es ist ein Leichtes, dies in einem großen Code-Commit zu verstecken, was keine Auswirkungen auf die Unit-Tests hat. Für alle Beteiligten ist alles normal – bis auf die Shell zugegriffen und bösartiger Code ausgeführt wird.
Kann man die Gefahr von Python-Importen entschärfen?
Die Importfunktion von Python, die automatisch Top-Level-Code ausführt, ist ein echtes Problem für den Einsatz in Unternehmen.
Unternehmen sollten proaktiv Tools zur statischen Codeanalyse einsetzen, die die Existenz von Top-Level-Code erkennen. Sie sollten auch KI-Routinen einsetzen, die erkennen, wenn selten genutzte Bibliotheken heimlich bearbeitet werden.
Diese Schritte mildern das Risiko jedoch nur ab, sie beseitigen es nicht. Die Gefahr des Python-Imports ist ein Angriffsvektor, den jeder Betreuer einer Python-Codebasis im Auge behalten sollte.