Skip to main content

Cheat Sheet: Best Practices für Python-Sicherheit

Artikel von

Frank Fischer

NumPy Arbitrary Code Execution Vulnerability small

27. September 2021

0 Min. Lesezeit
Cheat Sheet zu Best Practices für Python-Sicherheit 2021 mit zehn Empfehlungen, darunter Datenbereinigung, Code-Scans und vorsichtige Deserialisierung.

2019 veröffentlichte Snyk sein erstes Python-Cheat-Sheet. Seitdem haben sich viele Aspekte der Python-Sicherheit verändert. Auf Grundlage unserer Erfahrungen als Unternehmen für Entwicklersicherheit und der Best Practices speziell für Python haben wir dieses aktualisierte Cheat Sheet zusammengestellt, damit Ihr Python-Code sicher bleibt. Bevor wir fortfahren, möchte ich Chibo und Daniel ganz besonders für ihre Unterstützung bei diesem Cheat Sheet danken!

Laden Sie das Cheat Sheet zu Best Practices für Python-Sicherheit von 2021 herunter

Diese Tipps zur Python-Sicherheit sehen wir uns an:

  1. Bereinigen Sie externe Daten immer

  2. Scannen Sie Ihren Code

  3. Seien Sie beim Herunterladen von Paketen vorsichtig

  4. Prüfen Sie die Lizenzen Ihrer Abhängigkeiten

  5. Verwenden Sie nicht die systemweite Standardversion von Python

  6. Nutzen Sie die Unterstützung von Python für virtuelle Umgebungen

  7. Setzen Sie DEBUG = False in der Produktionsumgebung

  8. Seien Sie bei der Zeichenkettenformatierung vorsichtig

  9. (De-)Serialisieren Sie äußerst vorsichtig

  10. Verwenden Sie Python-Typannotationen

Ein kurzer Hinweis, bevor wir beginnen: Die Daten von Snyk zum Python-Ökosystem sowie akademische Studien zeigen, dass Python nicht mehr oder weniger sicher ist als andere weit verbreitete Programmiersprachen. Dieses Cheat Sheet richtet sich speziell an Pythonistas. Wir empfehlen Ihnen, sich auch alle unsere anderen Cheat Sheets zur Sicherheit anzusehen, um zu erfahren, wie Sie in anderen Ökosystemen sicher bleiben.

1. Bereinigen Sie externe Daten immer

Externe Daten sind ein möglicher Angriffsvektor für jede Anwendung. Sie können für Injection-, XSS- oder Denial-of-Service-Angriffe (DOS) missbraucht werden. Eine allgemeine Regel für die Python-Sicherheit lautet daher, Daten aus externen Quellen immer zu bereinigen (also vertrauliche Informationen zu entfernen) – unabhängig davon, ob sie aus einem Benutzereingabeformular, dem Scraping einer Website oder einer Datenbankabfrage stammen. Bereinigen Sie die Daten außerdem sofort, wenn sie in die Anwendung gelangen, um eine unsichere Verarbeitung zu verhindern. So verringern Sie das Risiko, dass Ihre Anwendung versehentlich nicht bereinigte vertrauliche Daten verarbeitet.

Bei der Bereinigung ist es immer sinnvoller, zu prüfen, welche Eingaben zulässig sind, als zu versuchen, Ausnahmen abzufangen. Außerdem empfehlen wir gut gepflegte Bibliotheken zur Bereinigung. Hier sind zwei Beispiele:

  • schema ist „eine Bibliothek zur Validierung von Python-Datenstrukturen, etwa aus Konfigurationsdateien, Formularen, externen Diensten oder der Befehlszeilenverarbeitung, die aus JSON/YAML (oder anderen Formaten) in Python-Datentypen umgewandelt wurden.“

  • bleach ist „eine HTML-Bereinigungsbibliothek mit Allowlist, die Markup und Attribute maskiert oder entfernt.“

Wichtige Frameworks bieten eigene Bereinigungsfunktionen, etwa flask.escape() von Flask oder django.utils.html.escape() von Django. Ziel dieser Funktionen ist es, potenziell bösartige HTML-Eingaben wie die folgende abzusichern:

>>> import bleach
>>> bleach.clean('an XSS <script>navigate(...)</script> example')
'an XSS &lt;script&gt;navigate(...)&lt;/script&gt; example'

Dieser Ansatz hat jedoch eine Einschränkung: Bibliotheken eignen sich nicht für alle Fälle, sondern sind auf ihren jeweiligen Bereich spezialisiert. Lesen Sie unbedingt bis zum Ende dieses Beitrags weiter, um mehr über den Umgang mit anderen Datenformaten wie XML zu erfahren, die ebenfalls schädliche Daten enthalten können.

Eine weitere häufig genutzte Möglichkeit ist, das Rendern von HTML Template-Engines wie Jinja zu überlassen. Sie bieten zahlreiche Funktionen, darunter automatisches Escaping zum Schutz vor XSS mithilfe von MarkupSafe.

Bei der Bereinigung geht es auch darum, zu verhindern, dass Daten als Befehl ausgeführt werden. Ein typisches Beispiel ist eine SQL-Injection. Statt Zeichenketten und Variablen zu einer SQL-Abfrage zusammenzufügen, empfiehlt es sich, benannte Parameter zu verwenden. So können Sie der Datenbank mitteilen, was als Befehl und was als Daten zu behandeln ist.

# Instead of this …
cursor.execute(f"SELECT admin FROM users WHERE username = '{username}'");
# ...do this...
cursor.execute("SELECT admin FROM users WHERE username = %(username)s", {'username': username}); 

Noch besser ist es, ein Object-Relational Mapping (ORM) wie sqlalchemy zu verwenden. Damit könnte die Beispielabfrage so aussehen:

query = session.query(User).filter(User.name.like('%{username}'))

Das Ergebnis: besser lesbarer Code und ORM-Optimierungen wie Caching sowie mehr Sicherheit und Performance!

Weitere Informationen finden Sie in unserem Cheat Sheet zu SQL-Injections.

2. Scannen Sie Ihren Code

Entwicklern steht eine große Auswahl an Tools für die statische Codeanalyse zur Verfügung, mit denen sie die Python-Sicherheit verbessern können. Sehen wir uns drei verschiedene Tool-Kategorien an.

Zunächst die Kategorie der Linter. PEP8 dient seit Jahrzehnten als Styleguide für Python. Verschiedene Tools (auch in IDEs integriert) prüfen Code anhand dieses Styleguides, darunter pep8, pylint, flake8 und weitere.

Tools wie bandit wandeln Code in einen abstrakten Syntaxbaum (AST) um und führen Abfragen darauf aus, um typische Sicherheitsprobleme zu finden. Damit gehen sie über die üblichen Linter hinaus, die auf syntaktischer Ebene arbeiten. bandit ist jedoch durch seine Zwischendarstellung und Performance eingeschränkt. So kann bandit beispielsweise keine Probleme im Datenfluss erkennen (bekannt als Taint-Analyse), die schwerwiegende Schwachstellen verursachen können – etwa Injections wie SQL-Injections oder XSS.

Schließlich führen Tools für Static Application Security Testing (SAST) wie Snyk Code eine semantische Analyse durch und berücksichtigen dabei auch komplexe Probleme über mehrere Dateien hinweg. Anders als andere Tools dieser Kategorie ist Snyk Code entwicklerfreundlich: Der Scan ist schnell und das Tool lässt sich in die IDE integrieren (oder direkt über die Befehlszeile nutzen). Snyk Code erklärt seine äußerst präzisen Ergebnisse und bietet Unterstützung, einschließlich Beispielen zur Behebung von Python-Sicherheitsproblemen. Darüber hinaus ist der Einstieg einfach und die Nutzung für Open Source kostenlos (mit einer begrenzten Anzahl zusätzlicher Tests für Nicht-OSS-Projekte).

3. Seien Sie beim Herunterladen von Paketen vorsichtig

Pakete lassen sich einfach installieren, können aber auch leicht Python-Sicherheitslücken einführen. Entwickler verwenden üblicherweise den Standardpaketmanager für Python (pip), der den Python Package Index (PyPI) nutzt. Daher ist es wichtig zu verstehen, wie Pakete zu PyPI hinzugefügt werden.

PyPI verfügt über ein Verfahren, um Sicherheitsbedenken zu melden. Wird ein schädliches Paket oder ein Problem bei PyPI gemeldet, wird es bearbeitet. Pakete, die zu PyPI hinzugefügt werden, werden jedoch nicht überprüft – eine solche Erwartung wäre gegenüber den Freiwilligen, die PyPI pflegen, unrealistisch.

Gehen Sie daher davon aus, dass PyPI schädliche Pakete enthalten kann, und handeln Sie entsprechend. Recherchieren Sie das Paket, das Sie installieren möchten, und achten Sie genau auf die Schreibweise des Paketnamens (ein Paket, dessen Name einem häufigen Schreibfehler bei einem beliebten Paket entspricht, könnte schädlichen Code ausführen). Prüfen Sie ein Paket vor dem Herunterladen mit Snyk Advisor.

Snyk Advisor-Suchergebnisse für „django“ mit Django-Paketen, Beschreibungen, Versionen und Paket-Integritätswerten.

Eine kurze Suche nach einem Paket in Snyk Advisor liefert zahlreiche Informationen zum Paket, seiner Unterstützung durch die Community, seiner Fehler- und Fehlerbehebungshistorie und vielem mehr. Snyk Advisor zeigt außerdem den Installationsbefehl oben auf der Ergebnisseite an. Kopieren Sie am besten diese Schreibweise, um Typosquatting zu vermeiden. Snyk Advisor zeigt Ihnen, ob Sie einem Paket vertrauen sollten. Sie können den Verlauf der Sicherheitsprobleme und die Zeit bis zu ihrer Behebung einsehen.

Eine weitere Best Practice ist die Verwendung virtueller Umgebungen, um Projekte voneinander zu isolieren. Verwenden Sie außerdem pip freeze oder einen vergleichbaren Befehl, um Änderungen in der Umgebung in der Liste der Anforderungen festzuhalten.

Mit stets aktuellen Referenzen basiert Snyk Open Source auf einer branchenführenden Schwachstellendatenbank, die Sicherheitsprobleme und mögliche Behebungen erfasst. Snyk Open Source scannt anhand der Anforderungen und liefert konkrete Informationen zu gefundenen Schwachstellen in direkten und transitiven Abhängigkeiten. Außerdem unterstützt es Sie dabei, diese umgehend zu beheben.

4. Prüfen Sie die Lizenzen Ihrer Abhängigkeiten

Wenn Sie ein Open-Source-Projekt verwenden möchten, sollten Sie sich mit dessen Lizenz vertraut machen. Open-Source-Projekte sind kostenlos verfügbar und nutzbar, können aber dennoch an Bedingungen geknüpft sein. Diese betreffen üblicherweise die Nutzung der Software, die Pflicht, Änderungen an der Software öffentlich zugänglich zu machen, und ähnliche Anforderungen. Machen Sie sich mit den erforderlichen Open-Source-Lizenzen der von Ihnen verwendeten Projekte vertraut, damit Sie keine rechtlichen Risiken eingehen.

Entscheiden Sie sich für eine restriktivere Lizenz als erwartet (GPL, SSPL usw.), können Sie sich in eine schwierige Lage bringen: Sie müssen dann entweder die Lizenzbedingungen einhalten oder das Projekt nicht mehr verwenden. Wenn Sie außerdem Änderungen an einem Projekt ohne Lizenz vornehmen müssen, könnten Sie gegen das Urheberrecht verstoßen.

Damit Ihr Projekt nachhaltig ist und Sie sich keinen unnötigen Sicherheits- und Rechtsrisiken im Zusammenhang mit Python aussetzen, sollten Sie die Lizenzen und Schwachstellen in den Abhängigkeiten Ihres Projekts scannen und Probleme beheben.

Snyk Open Source unterstützt Sie beim Management der Compliance mit Open-Source-Lizenzen. Die Lösung bietet Entwicklern einen unkomplizierten Weg zu umfassender Transparenz und ermöglicht zugleich eine flexible Governance.

5. Verwenden Sie nicht die systemweite Standardversion von Python

Auf den meisten POSIX-Systemen ist bereits eine Python-Version installiert. Das Problem bei den meisten vorinstallierten Python-Distributionen: Sie sind nicht aktuell.

Verwenden Sie daher die neueste für Ihr System verfügbare Python-Version sowie die offiziellen Container für die Ausführung von Python und halten Sie beides aktuell. Snyk unterstützt Sie dabei: Scannen Sie Ihre Container mit Snyk Container auf erforderliche Updates und prüfen Sie Ihre Abhängigkeiten mit Snyk Open Source.

6. Verwenden Sie virtuelle Python-Umgebungen

Python ermöglicht es, die Anwendungsentwicklung in virtuelle Umgebungen aufzuteilen. Eine virtuelle Umgebung isoliert den Python-Interpreter sowie die darin installierten Bibliotheken und Skripte. Das bedeutet: Statt für alle Projekte dieselbe globale Python-Version und dieselben globalen Python-Abhängigkeiten zu verwenden, können Sie projektspezifische virtuelle Umgebungen mit jeweils eigenen Python- und Python-Abhängigkeitsversionen einrichten.

Die meisten IDEs, CLIs und Dashboards wie Anaconda Navigator bieten integrierte Funktionen für den Wechsel zwischen virtuellen Umgebungen.

Profi-Tipp: Ab Python 3.5 wird die Verwendung von venv empfohlen. Mit Version 3.6 wurde pyvenv als veraltet eingestuft.

Virtuelle Umgebungen erleichtern die Entwicklung, Paketierung und Bereitstellung sicherer Python-Anwendungen. Ihre Verwendung wird dringend empfohlen. Weitere Informationen finden Sie in der Python-Dokumentation zu venv.

7. Setzen Sie DEBUG = False in der Produktionsumgebung

In einer Entwicklungsumgebung sind ausführliche Fehlermeldungen sinnvoll. In der Produktionsumgebung sollten Sie jedoch verhindern, dass Informationen preisgegeben werden, die Angreifern Einblicke in Ihre Umgebung, Bibliotheken oder Ihren Code ermöglichen.

Bei den meisten Frameworks ist das Debugging standardmäßig aktiviert. Bei Django ist es beispielsweise in settings.py eingeschaltet. Stellen Sie sicher, dass Sie das Debugging in der Produktionsumgebung auf False setzen, damit Angreifer keine vertraulichen Informationen über Ihre Anwendung erhalten.

Profi-Tipp: Es empfiehlt sich, Ihr Continuous-Deployment-System bei der Bereitstellung in der Produktionsumgebung überprüfen zu lassen, ob diese Einstellung deaktiviert ist.

8. Seien Sie bei der Zeichenkettenformatierung vorsichtig

Obwohl Python auf dem Prinzip beruht, dass es für eine Aufgabe nur einen Weg geben sollte, bietet die Sprache tatsächlich vier Möglichkeiten zur Formatierung von Zeichenketten (drei Methoden für Versionen vor Python 3.6).

Die Formatierung von Zeichenketten ist nach und nach flexibler und leistungsfähiger geworden (insbesondere f-Strings sind interessant). Mit der Flexibilität steigt jedoch auch das Potenzial für Exploits. Daher sollten Python-Nutzer sorgfältig abwägen, wie sie Zeichenketten mit von Nutzern bereitgestellten Eingaben formatieren.

Python enthält ein integriertes Modul namens string. Dieses Modul umfasst die Klasse Template, mit der sich Template-Zeichenketten erstellen lassen.

Sehen wir uns das folgende Beispiel an.

from string import Template
greeting_template = Template(“Hello World, my name is $name.”)
greeting = greeting_template.substitute(name=”Hayley”)

Im obigen Code wird die Variable greeting wie folgt ausgewertet: „Hello World, my name is Hayley.“

Dieses Zeichenkettenformat ist etwas umständlich, da es eine Import-Anweisung erfordert und weniger flexibel mit Datentypen umgeht. Außerdem wertet es Python-Anweisungen nicht wie f-Strings aus. Dadurch eignen sich Template-Zeichenketten hervorragend für den Umgang mit Benutzereingaben.

Noch ein kurzer Hinweis zur Formatierung von Zeichenfolgen: Seien Sie bei rohem SQL besonders vorsichtig, wie oben erwähnt.

9. Sehr vorsichtig (de)serialisieren

Python bietet mit dem Modul pickle einen integrierten Mechanismus zum Serialisieren und Deserialisieren von Python-Objekten, das sogenannte „Pickling“. Dieser gilt als unsicher. Daher empfiehlt es sich, ihn sehr vorsichtig und nur mit vertrauenswürdigen Datenquellen zu verwenden.

Der neue De-facto-Standard für die Serialisierung und Deserialisierung ist YAML. Das Paket PyYAML bietet einen Mechanismus, um benutzerdefinierte Datentypen in YAML und zurück zu serialisieren. PyYAML birgt jedoch diverse potenzielle Angriffsvektoren. Eine einfache, aber wirksame Maßnahme zur sicheren Verwendung von PyYAML ist, als Loader yaml.SafeLoader() statt yaml.Loader() zu verwenden.

Data = yaml.load(input_file, Loader=yaml.SafeLoader)

Dadurch wird das Laden benutzerdefinierter Klassen verhindert, Standardtypen wie Hashes und Arrays werden jedoch unterstützt.

Ein weiterer typischer Anwendungsfall ist XML. Häufig kommen Standardbibliotheken zum Einsatz, die jedoch anfällig für typische Angriffe sind – insbesondere DoS-Angriffe oder die Expansion externer Entitäten (dabei wird auf eine externe Quelle verwiesen). Eine gute erste Schutzmaßnahme ist das Paket defusedxml. Es schützt vor diesen typischen XML-Sicherheitsproblemen.

Zusätzlicher Tipp ohne Sicherheitsbezug: Verwenden Sie Python-Typannotationen

Mit Version 3.5 wurden Typhinweise eingeführt. Die Python-Laufzeitumgebung erzwingt Typannotationen zwar nicht, doch Tools wie Typprüfer, IDEs, Linter, SAST-Tools und andere profitieren davon, wenn Entwicklerinnen und Entwickler genauere Angaben machen. Hier ein Beispiel zur Veranschaulichung:

MODE = Literal['r', 'rb', 'w', 'wb']
def open_helper(file: str, mode: MODE) -> str:
    ...
open_helper('/some/path', 'r')  # Passes type check
open_helper('/other/path', 'typo')  # Error in type checker

Literal[...] wurde mit Version 3.8 eingeführt und wird von der Laufzeitumgebung nicht erzwungen (in unserem Beispiel können Sie beliebige Zeichenfolgen übergeben). Typprüfer können jedoch erkennen, wenn ein Parameter außerhalb des zulässigen Bereichs liegt, und Sie warnen. Diese Funktion ist äußerst nützlich – nicht nur für die Python-Sicherheit.

Hinweis: Da die Laufzeitumgebung Typhinweise nicht erzwingt, ist ihr Nutzen für die Sicherheit begrenzt.

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 snyk container custom base recommendations
Blog

Evo Agentic AppSec: Sicherheit, die mit der KI-Entwicklung Schritt hält

KI-gestützte Entwicklung überholt herkömmliche Security-Workflows. Snyk Agentic AppSec setzt Security-Agenten ein, die Schwachstellen kontinuierlich finden, beheben und überprüfen – während Menschen die Maßstäbe festlegen.

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 Dependency-Upgrades. Eine Lösung zählt nur, wenn die Sicherheitslücke behoben ist und Build sowie Tests weiterhin erfolgreich sind.

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.