Skip to main content

Die Gefahren von assert in Python

Artikel von
Headshot of Dhruv Patel

Dhruv Patel

hero assert in python

18. August 2022

0 Min. Lesezeit

Es 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:

assert expression

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:

>>> assert 'hi' == 'there'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

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.

>>> assert 'hi' == 'there', 'Values do not match!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Values do not match!

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:

def simpleInterest(p, t, r):
print('The principal is', p)
assert isinstance(p, int) and p > 0, "Principal must be a positive integer"
print('The time period is', t)
assert isinstance(t, int) and t > 0, "Time must be a positive integer"
print('The rate of interest is', r)
assert isinstance(r, int) and r > 0, "Rate of interest must be a positive integer"
simpleInterest = (p * t * r) / 100
print('The Simple Interest is', simpleInterest)
return simpleInterest

simpleInterest(3, 5, 8)

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:

python safe_assert_example.py

Sie sollten die unten gezeigte Ausgabe mit einem einfachen Zinsertrag von 1,2 erhalten:

PS E:\Sample\Extra\Assert Demo> python safe_assert_example.py
The principal is 3
The time period is 5
The rate of interest is 8
The Simple Interest is 1.2

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“:

simpleInterest(3, "time", 8)

Führen Sie das Programm nun mit diesem Befehl erneut aus:

python safe_assert_example.py

Diesmal sollte die folgende Fehlermeldung erscheinen:

PS E: \Sample\Extra\Assert Demo» python safe assert example.py
The principal is 3
The time period is time
Traceback (most recent call last):
    File "E: \Sample\Extra\Assert Demo\safe assert example.py", line 12, in <module> simpleInterest(3, "time", 8)
    File "E: \Sample\Extra\Assert Demo\safe assert example.py", line 5, in simpleInterest assert isinstance(t, int) and t > 0, "Time must be a positive integer"
AssertionError: Time must be a positive integer

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:

python -O safe_assert_example.py

Das gibt Folgendes zurück:

PS E:\Sample\Extra\Assert Demo› python -0 safe assert example.py
The principal is 3
The time period is time
The rate of interest is 8
Traceback (most recent call last):
    File "E:\Sample\Extra\Assert Demo\safe assert example.py", line 12, in <module> simpleInterest(3, "time", 8)
    File "E:\Sample\Extra\Assert Demo\safe assert example.py", line 8, in simpleInterest simpleInterest = (p * t * r)/100
TypeError: unsupported operand type(s) for /: 'str' and 'int'

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 simpleInterest abzufangen, 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:

def authorize_admin_user(user_roles):
    assert isinstance(user_roles,list) and user_roles != [], "No user roles found"

    assert 'admin' in user_roles, "No admin role found."
    print("You have full access to the application.")

authorize_admin_user(['admin','user'])

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.

Run python unsafe_assert_example.py:

$ python unsafe_assert_example.py
You have full access to the application

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:

authorize_admin_user(['user'])

Führen Sie das Programm anschließend aus und prüfen Sie die Ausgabe:

$ python unsafe_assert_example.py
Traceback (most recent call last):
  File "C:\Projects\ContentLabEditing\python\unsafe_assert_example.py", line 6, in <module>
    authorize_admin_user(['user'])
  File "C:\Projects\ContentLabEditing\python\unsafe_assert_example.py", line 3, in authorize_admin_user
    assert 'admin' in user_roles, "No admin role found."
AssertionError: No admin role found.

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:

python -O unsafe_assert_example.py

Die Ausgabe entspricht der Abbildung unten. Obwohl die Liste keine admin-Rolle enthielt, war die Administratorautorisierung erfolgreich, weil assert nicht ausgeführt wurde.

PS E:\Sample\Extra\Assert Demo> python -0 unsafe_assert_example.py
You have full access to the application
You have full access to the application
PS E:\Sample\Extra\Assert Demo>

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.

Weiterlesen

blog feature ai lilac
Blog

Mit agentischer Behebung Ihren Schwachstellen-Backlog in Pull Requests verwandeln

Der Evo Remediation Agent ist jetzt in der öffentlichen Vorschau verfügbar und erweitert Evo Agentic AppSec um die automatisierte Auflösung von Abhängigkeiten. AppSec-Teams können jetzt kontinuierliche Behebungskampagnen durchführen

AI Background min crop
Blog

KI ruft alle Risiken auf den Plan, die Sie akzeptiert haben: Sieben Erkenntnisse aus dem AI Security Panel: Unfiltered

KI macht Angriffe günstiger und schneller und legt Risiken offen, die Unternehmen bereits tragen. Vier Sicherheitsverantwortliche erklären, warum Abwehr in Maschinengeschwindigkeit und schnellere Behebung jetzt unverzichtbar sind.

blog feature ai violet
Blog

VulnBump: Können KI-Agenten anfällige Abhängigkeiten beheben, ohne den Build zu beschädigen?

VulnBump testet KI-Agenten anhand von 307 realen Upgrades von Abhängigkeiten. Eine Behebung zählt nur, wenn die Sicherheitslücke geschlossen ist und Build und Tests weiterhin erfolgreich sind.