Die Gefahren von assert in Python
Dhruv Patel
18. August 2022
0 Min. LesezeitEs gibt viele Möglichkeiten, Fehler in Python-Code zu finden: den integrierten Debugger (pdb), eine ausreichende Zahl von Unit-Tests, einen Debugger in einer IDE wie Pycharm oder Visual Studio, try/catch-Anweisungen, if/else-Anweisungen, assert statements oder die bewährte Methode, jede Zeile Ihrer Codebasis mit print()-Anweisungen zu versehen, als käme das nie aus der Mode.
Mit assert-Anweisungen lassen sich Fehler schnell finden, und sie sind deutlich weniger aufdringlich als Unmengen von print-Anweisungen. Anders als print-Anweisungen können assert-Anweisungen jedoch unerwartete Risiken bergen!
In diesem Artikel erfahren Sie, wie Sie assert sicher verwenden und wodurch die Verwendung unsicher wird. Danach wissen Sie, wie Sie assert optimal einsetzen, ohne sich versehentlich Sicherheitsproblemen auszusetzen.
Python-assert-Anweisungen verwenden
Die Verwendung von assert ist einfach! Assert-Anweisungen sind einfache Anweisungen, das heißt, sie passen in eine Zeile Python-Code.
Hier sehen Sie ein einfaches Beispiel für eine assert-Anweisung:
Mit der obigen Anweisung bestätigen Sie, dass der Ausdruck zu True ausgewertet wird – ähnlich wie bei einer booleschen Prüfung.
Ist der Ausdruck False, wird eine Ausnahme ausgelöst. Zum Beispiel:
Damit Sie einen Stacktrace leichter durchsehen können, lässt sich eine Assertion-Nachricht angeben, die Teil des AssertionError ist. Das kann bei komplexen Debugging-Szenarien hilfreich sein.
Die integrierte Python-Variable __debug__ muss bei der Verwendung von assert-Anweisungen auf True gesetzt sein. Ist sie auf False gesetzt, werden assert-Anweisungen zur Laufzeit nicht ausgeführt. Das ist ein ernstes Problem, denn wenn Python im optimierten Modus ausgeführt wird (was in Produktionsumgebungen häufig durch Setzen des Befehlszeilen-Flags PYTHONOPTIMIZE, -O, geschieht), wird die Variable __debug__ auf False gesetzt. Dadurch werden assert-Anweisungen deaktiviert, was möglicherweise unbeabsichtigt Sicherheitslücken in Ihr Projekt einführt. Weiter unten gehen wir genauer darauf ein.
Bei korrekter Verwendung ist assert ein leistungsstarkes Debugging-Werkzeug. Je komplexer die Verwendung jedoch ist, desto größer ist das Risiko, während der Entwicklung Sicherheitslücken einzuführen.
Kurz gesagt: Assert-Anweisungen sind beim Debugging von Python-Anwendungen äußerst nützlich, eignen sich aber nicht für die normale Fehlerbehandlung oder den Kontrollfluss, da sie entweder:
die Anwendung durch das Auslösen einer Ausnahme anhalten, was zu Ausfällen in der Produktionsumgebung führen kann.
unerwünschte Nebenwirkungen (darunter möglicherweise auch Sicherheitslücken) in Ihrer Anwendung verursachen, wenn der Debug-Modus deaktiviert ist und die Python-Laufzeitumgebung Anweisungen stillschweigend überspringt.
assert sicher verwenden
Sehen wir uns an, wie Sie mit Assert-Anweisungen ein Programm debuggen können. Dazu untersuchen wir eine Beispielanwendung, die einfache Zinsen berechnet.
Installieren Sie zunächst eine stabile Python-Version. Öffnen Sie anschließend einen Ordner und erstellen Sie eine Python-Datei mit dem Namen safe_assert_example.py. Sie können einen beliebigen unterstützten Code-Editor verwenden.
Fügen Sie den folgenden Code zu safe_assert_example.py hinzu:
Dieses Programm definiert die Funktion simpleInterest und berechnet einfache Zinsen anhand von Kapital, Laufzeit und Zinssatz.
Für eine korrekte Zinsberechnung müssen Sie für Kapital, Laufzeit und Zinssatz positive Ganzzahlen eingeben. In diesem Beispiel prüfen assert-Anweisungen, ob die Werte p, t und r positive Ganzzahlen sind. Ist ein Wert keine positive Ganzzahl, gibt das Programm eine aussagekräftige Fehlermeldung zurück.
Probieren Sie es aus! Führen Sie das Programm mit dem folgenden Befehl aus:
Sie sollten die unten gezeigte Ausgabe mit einem einfachen Zinsertrag von 1,2 erhalten:
Wie Sie sehen, läuft das Programm problemlos und gibt keine Fehlermeldung zurück.
Sehen Sie sich jetzt an, was passiert, wenn Sie das Programm mit einer ungültigen Eingabe ausführen. Ändern Sie den Wert von t von 5 in die Zeichenfolge „time“:
Führen Sie das Programm nun mit diesem Befehl erneut aus:
Diesmal sollte die folgende Fehlermeldung erscheinen:
Diese Ausgabe enthält einen AssertionError. Die Ausnahme zeigt, dass die assert-Anweisung wie vorgesehen funktioniert und das ungültige Funktionsargument erfolgreich abgefangen hat.
In diesem Beispiel hat uns die Assertion beim Debuggen des Programms geholfen und die Programmausführung angehalten, sobald die Assertion fehlschlug.
Zur Erinnerung: Wenn Sie das Programm im optimierten Modus ausführen (indem Sie das Befehlszeilen-Flag PYTHONOPTIMIZE, -O, setzen), werden assert-Anweisungen stillschweigend deaktiviert. Sehen Sie sich nun an, wie sich dieses Verhalten auf die Anwendung auswirkt.
Lassen Sie „`time=“ als Wert für t stehen und führen Sie das Programm zur Berechnung einfacher Zinsen mit dem folgenden Befehl im optimierten Modus aus:
Das gibt Folgendes zurück:
Obwohl das Programm ein ungültiges Funktionsargument enthält, ist der erwartete AssertionError in der obigen Ausgabe nicht enthalten. Stattdessen gibt Python einen TypeError aus, da Sie versuchen, Variablen vom Typ Integer und String zu multiplizieren. Das liegt daran, dass die assert-Anweisungen nicht ausgeführt wurden. Daher sollten Sie Alternativen in Betracht ziehen, zum Beispiel:
Typannotationen hinzufügen, um fehlerhafte Aufrufe von
simpleInterestabzufangen, bevor der Code ausgeführt wird.Zur Laufzeit mit
if-Anweisungen statt mit Assertions die Typen prüfen.
assert unsicher verwenden
assert sollte nur für Tests und zum Debuggen verwendet werden – nicht in Produktionsumgebungen. Da assert-Anweisungen nur ausgeführt werden, wenn die Variable __debug__ auf True gesetzt ist, kann ein Python-Interpreter sie deaktivieren.
Wie das obige Beispiel zeigt, werden assert-Anweisungen durch die Ausführung von Python im optimierten Modus mit -O deaktiviert, da dadurch __debug__ auf False gesetzt wird.
Deshalb ist es nicht sicher, assert-Anweisungen für etwas zu verwenden, das in einer Produktionsumgebung ausgeführt werden muss. Verwenden Sie Assertions zum Beispiel niemals, um Token oder Benutzereingaben zu validieren. Diese Anweisungen werden in der Produktionsumgebung nicht ausgeführt. Daher werden Token und Benutzereingaben nicht validiert, wodurch möglicherweise Sicherheitslücken in Ihrer Anwendung entstehen.
Um zu veranschaulichen, wie schwerwiegend die Verwendung von assert zur Validierung in einer Produktionsumgebung ist, betrachten wir eine Benutzerautorisierungsfunktion. Sie erhält ein Array von Benutzern und lässt sie je nach Zugriffsebene fortfahren. Zunächst prüft das Programm mit assert, ob die Liste bzw. das Array nicht null ist und eine Listeninstanz darstellt. Anschließend erhält der Administrator je nach Rolle vollständigen Zugriff auf die Anwendung. Ist die Rolle „admin“ in der Benutzerliste vorhanden, wird kein AssertionError ausgelöst. Ist keine Administratorrolle in der Liste zu finden, wird dagegen ein Fehler ausgelöst.
Fügen Sie als Nächstes diesen Code in eine Datei namens unsafe_assert_example.py ein:
Die Funktion authorize_admin_user prüft die Rollen des Benutzers. Ist der Benutzer Administrator, wird angezeigt, dass er vollständigen Zugriff auf die Anwendung hat. Normalerweise werden die Rollen eines Benutzers aus der Datenbank geladen. Ist die Rolle „admin“ darunter, erhält der Benutzer vollständigen Zugriff auf die App. Andernfalls schlägt assert fehl und löst eine Ausnahme aus.
In der letzten Zeile der Datei wird die Funktion authorize_admin_user aufgerufen und eine Liste mit zwei Rollen übergeben: admin und user.
Wie erwartet erhält der Benutzer vollständigen Zugriff auf die Anwendung.
Rufen wir die Benutzerrollenfunktion ohne Administratorrolle in der Liste auf. Ändern Sie die letzte Codezeile in unsafe_assert_example.py wie folgt:
Führen Sie das Programm anschließend aus und prüfen Sie die Ausgabe:
Wie erwartet löst die Funktion einen AssertionError aus, da „admin“ nicht in der Rollenliste enthalten war.
Führen Sie dasselbe Programm nun mit optimierter Ausgabe aus:
Die Ausgabe entspricht der Abbildung unten. Obwohl die Liste keine admin-Rolle enthielt, war die Administratorautorisierung erfolgreich, weil assert nicht ausgeführt wurde.
Wenn Sie den Funktionsaufruf ändern und eine Liste mit Ganzzahlen übergeben, zeigt die Ausführung mit derselben optimierten Ausgabe außerdem, dass assert nur zum Debuggen und nicht zur Validierung verwendet werden sollte.
Ändern Sie den Funktionsaufruf in authorize_admin_user([1,2]) und führen Sie ihn mit demselben Befehl aus: python -O unsafe_assert_example.py.
Die Ausgabe des Programms bleibt unverändert.
In unserem Beispiel mit dem einfachen Zinsrechner waren die Folgen gering, als unsere assert-Anweisungen nicht ausgeführt wurden. Zwar erhielten wir nicht die gewünschte Fehlermeldung, aber anhand der Python-Fehlermeldung konnten wir nachvollziehen, was schiefgelaufen war. Noch wichtiger: Da wir assert-Anweisungen sicher zum Debuggen verwendeten, haben wir keine Sicherheitslücken eingeführt.
In diesem Beispiel haben wir assert unsicher verwendet und unsere Python-Anwendung angreifbar gemacht, indem wir einem Benutzer ohne Administratorrechte Zugriff als Administrator gewährt haben.
Wenn Sie diese Beispiele weiter ausprobieren möchten, finden Sie den gesamten Code aus diesem Artikel in diesem Repository.
Do's und Don'ts bei assert
Mit assert können Entwickler Python-Code leichter debuggen und dabei weniger Codezeilen schreiben. Bei unsachgemäßer Verwendung kann es jedoch versehentlich Sicherheitsprobleme in Ihren Anwendungen verursachen.
Assertions in einer Produktionsumgebung zu deaktivieren, kann verheerende Folgen haben. Dadurch können verschiedene Hintertüren und Sollbruchstellen in der Anwendung entstehen, die Angreifer ausnutzen können.
Die Hauptaufgabe einer Assertion sollte darin bestehen, die Ursache eines Fehlers einzugrenzen. Sie sollte niemals zur normalen Fehlerbehandlung verwendet werden. Assertions können hilfreich sein, sollten aber zum Debuggen und Testen dienen – nicht dazu, den Ablauf der Logik eines Programms oder einer Anwendung zu steuern. Verwenden Sie sie ausschließlich in sicheren Situationen. Als Alternativen zu assert sind Unit-Tests, Debugger, bedingte Anweisungen und Validatoren bessere und sicherere Optionen.
Nachdem Sie nun wissen, wie Sie assert sicher verwenden, lesen Sie den Spickzettel zu den Python-Best Practices, um mehr darüber zu erfahren, wie Sie Ihre Anwendungen auf allen Plattformen und in sämtlichen Umgebungen schützen.
Weitere Ressourcen zu Python-Entwicklung und -Sicherheit
Sie können auch unser kostenloses Online-Tool Python-Code-Checker ausprobieren, um zu sehen, wie die Snyk-Code-Engine Ihren Code auf Sicherheits- und Qualitätsprobleme analysiert.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



