|
| 1 | +.. SPDX-FileCopyrightText: 2023 cusy GmbH |
| 2 | +.. |
| 3 | +.. SPDX-License-Identifier: BSD-3-Clause |
| 4 | +
|
| 5 | +Eigener Code |
| 6 | +============ |
| 7 | + |
| 8 | +Angriffe auf die Lieferkette gehen nicht nur von :doc:`dependencies` aus, auch |
| 9 | +euer eigener Code kann Angriffspunkte liefern. Ein fest im Quellcode |
| 10 | +hinterlegtes PyPI-Token liefert, sobald es in ein öffentliches Repository |
| 11 | +hochgeladen wurde, alles, was für einem Angriff benötigt wird und euer Konto zu |
| 12 | +kompromittieren und bösartige Pakete unter eurem Namen zu veröffentlichen. |
| 13 | +Abgesehen von Secrets verbergen sich häufige Sicherheitsfehler in alltäglichen |
| 14 | +Codemustern, die bei einem Code-Review zunächst unbedenklich erscheinen und von |
| 15 | +Menschen übersehen werden können. Diese mit einem Linter aufzuspüren, ist die |
| 16 | +erste Verteidigungsstufe. |
| 17 | + |
| 18 | +Das ewige Geheimnis |
| 19 | +------------------- |
| 20 | + |
| 21 | +Durchgesickerte Zugangsdaten sind der Ausgangspunkt für viele |
| 22 | +Sicherheitsverletzungen in der Lieferkette. Ein offengelegtes :term:`PyPI`-Token |
| 23 | +ermöglicht, mit Hintertüren versehene Versionen eurer Pakete zu veröffentlichen. |
| 24 | +Eine offengelegte Datenbank-URL ermöglicht, Daten zu entwenden. Und doch ist ein |
| 25 | +solches Muster weit verbreitet. Besser ist die Verwendung von |
| 26 | +Umgebungsvariablen: |
| 27 | + |
| 28 | +.. code-block:: python |
| 29 | +
|
| 30 | + import os |
| 31 | +
|
| 32 | + DATABASE_KEY = os.environ["DB_KEY"] |
| 33 | + DATABASE_URL = os.environ["DB_URL"] |
| 34 | +
|
| 35 | +.. warning:: |
| 36 | + Git vergisst nie: wenn ihr ein Secret einmal durch Git verwaltet habt, bleibt |
| 37 | + es für immer in der Historie eures Repositories erhalten. Es in einem |
| 38 | + späteren Commit einfach zu löschen, hilft nicht wirklich. Alle, die Zugriff |
| 39 | + auf das Repository haben, können diese Anmeldedaten wieder extrahieren. Bei |
| 40 | + Angriffen wird oft zunächst die Git-Historie nach Geheimnissen durchforstet, |
| 41 | + und ein einmal veröffentlichts PyPI-Token oder Cloud-Anmeldedaten sind oft |
| 42 | + der erste Schritt bei einer Kompromittierung der Lieferkette. |
| 43 | + |
| 44 | +Kryptografische Schwachstellen |
| 45 | +------------------------------ |
| 46 | + |
| 47 | +Weitere häufige Sicherheitslücken sind kryptografische Schwachstellen wie |
| 48 | +`MD5 <https://de.wikipedia.org/wiki/Message-Digest_Algorithm_5>`_ und `SHA-1 |
| 49 | +<https://de.wikipedia.org/wiki/Secure_Hash_Algorithm#SHA-1>`_. MD5-Kollisionen |
| 50 | +wurden erstmals 2004 nachgewiesen und SHA1-Kollisionen 2017. Es können also |
| 51 | +Kollisionen erzeugt werden durch andere Eingaben, die denselben Hash-Wert |
| 52 | +ergeben. Dies ermöglicht die Fälschung von Zertifikaten, die Manipulation von |
| 53 | +Downloads oder die Umgehung von Integritätsprüfungen. Verwendet daher keines der |
| 54 | +beiden Verfahren für Sicherheitszwecke sondern stattdessen `SHA256 oder besser |
| 55 | +<https://de.wikipedia.org/wiki/SHA-2>`_: |
| 56 | + |
| 57 | +.. code-block:: python |
| 58 | +
|
| 59 | + import hashlib |
| 60 | +
|
| 61 | + digest = hashlib.sha256(payload).hexdigest() |
| 62 | +
|
| 63 | +Hängende Verbindungen |
| 64 | +--------------------- |
| 65 | + |
| 66 | +Das hier ist zwar subtil, aber dennoch gefährlich, da ein langsamer Server |
| 67 | +euren Prozess auf unbestimmte Zeit zum Stillstand bringen kann. Ein Angriff über |
| 68 | +einen solchen Server, mit dem eure Anwendung kommuniziert, kann jede Anfrage zum |
| 69 | +Erliegen bringen, euren Thread-Pool erschöpfen und einen |
| 70 | +Denial-of-Service-Angriff auslösen. Eure gesamte Anwendung kommt dann zum |
| 71 | +Stillstand, weil ihr einen Parameter vergessen habt. Daher solltet ihr immer |
| 72 | +einen Timeout angeben: |
| 73 | + |
| 74 | +.. code-block:: pycon |
| 75 | +
|
| 76 | + >>> import httpx |
| 77 | + >>> r = httpx.get("https://httpbin.org/get", timeout=30) |
| 78 | + httpx.ReadTimeout: The read operation timed out |
| 79 | +
|
| 80 | +.. _bandit: |
| 81 | + |
| 82 | +Erkennt Sicherheitslücken mit Ruff |
| 83 | +---------------------------------- |
| 84 | + |
| 85 | +:doc:`../qa/ruff` ist ein schneller Python-Linter, der umfassende |
| 86 | +Sicherheitsregeln von :ref:`Bandit <bandit>` enthält: |
| 87 | + |
| 88 | +.. code-block:: console |
| 89 | +
|
| 90 | + $ uvx ruff check --select S . |
| 91 | +
|
| 92 | +.. seealso:: |
| 93 | + Weitere Informationen findet ihr in der `Dokumentation zu den |
| 94 | + Ruff-Sicherheitsregeln |
| 95 | + <https://docs.astral.sh/ruff/rules/#flake8-bandit-s>`_. |
| 96 | + |
| 97 | +Für zukünftige Checks könnt ihr ``ruff`` ihn in der :file:`pyproject.toml`-Datei |
| 98 | +konfigurieren: |
| 99 | + |
| 100 | +.. code-block:: toml |
| 101 | +
|
| 102 | + [tool.ruff] |
| 103 | + lint.select = ["S"] |
| 104 | +
|
| 105 | +Die Sicherheitsregeln ``["S"]`` mit den Bandit-Prüfungen.spüren fest codierte |
| 106 | +Geheimnisse, schwache Verschlüsselung und unsichere Deserialisierung auf. Dabei |
| 107 | +läuft Ruff in weniger als einer Sekunde, sodass ihr es während der Eingabe in |
| 108 | +eurer IDE und vor jedem Commit ausführen könnt. Alle drei oben genannten |
| 109 | +Schwachstellen werden erkannt und noch viel mehr, :abbr:`u. a. (unter anderem)`: |
| 110 | + |
| 111 | ++--------+-----------------------------------------------------------------------+ |
| 112 | +| Regel | Beschreibung | |
| 113 | ++--------+-----------------------------------------------------------------------+ |
| 114 | +| `S105`_| fest codierte Geheimnisse | |
| 115 | ++--------+-----------------------------------------------------------------------+ |
| 116 | +| `S301`_| :doc:`/data-processing/serialisation-formats/pickle/index` und andere | |
| 117 | +| | unsichere Deserialisierung | |
| 118 | ++--------+-----------------------------------------------------------------------+ |
| 119 | +| `S307`_| Verwendung von :func:`eval` mit nicht vertrauenswürdigen Eingaben | |
| 120 | ++--------+-----------------------------------------------------------------------+ |
| 121 | +| `S113`_| fehlende Zeitüberschreitungen | |
| 122 | ++--------+-----------------------------------------------------------------------+ |
| 123 | +| `S324`_| schwache Kryptografie wie :abbr:`z. B. (zum Beispiel)` MD5-Kollisionen| |
| 124 | ++--------+-----------------------------------------------------------------------+ |
| 125 | +| `S608`_| SQL-Injection über String-Formatierung | |
| 126 | ++--------+-----------------------------------------------------------------------+ |
| 127 | + |
| 128 | +.. seealso:: |
| 129 | + * `flake8-bandit (S) <https://docs.astral.sh/ruff/rules/#flake8-bandit-s>`_ |
| 130 | + * `lint.flake8-bandit |
| 131 | + <https://docs.astral.sh/ruff/settings/#lintflake8-bandit>`_ |
| 132 | + |
| 133 | +Bandit könnt ihr auch in Jupyter Notebooks, :abbr:`IDEs (Integrated Development |
| 134 | +Wnvironments)` und :doc:`../git/advanced/hooks/prek` integrieren. |
| 135 | + |
| 136 | +Zudem könnt ihr :doc:`../qa/pysa` für `Taint |
| 137 | +<https://en.wikipedia.org/wiki/Taint_checking>`_-Analysen verwenden. |
| 138 | + |
| 139 | +Für GitHub-Repositories könnt ihr alternativ auch `CodeQL |
| 140 | +<https://codeql.github.com>`_ verwenden; :abbr:`s.a. (siehe auch)` |
| 141 | +`codeql-action |
| 142 | +<https://github.com/github/codeql-action/blob/main/README.md#usage>`_. |
| 143 | + |
| 144 | +Vertrauenswürdige Veröffentlichung |
| 145 | +---------------------------------- |
| 146 | + |
| 147 | +In einem früheren Abschnitt haben wir schon einige Hinweise gegeben, wie die |
| 148 | +Veröffentlichung von Python-Paketen auf :term:`PyPI` abgesichert werden kann: |
| 149 | + |
| 150 | +.. seealso:: |
| 151 | + * :ref:`secure-release-workflow` |
| 152 | + * :ref:`add_2fa` |
| 153 | + |
| 154 | +.. seealso:: |
| 155 | + * `Publishing package distribution releases using GitHub Actions CI/CD |
| 156 | + workflows |
| 157 | + <https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/>`_ |
| 158 | + |
| 159 | +.. _S105: https://docs.astral.sh/ruff/rules/hardcoded-password-string/ |
| 160 | +.. _S301: https://docs.astral.sh/ruff/rules/suspicious-pickle-usage/ |
| 161 | +.. _S307: https://docs.astral.sh/ruff/rules/suspicious-eval-usage/ |
| 162 | +.. _S113: https://docs.astral.sh/ruff/rules/request-without-timeout/ |
| 163 | +.. _S324: https://docs.astral.sh/ruff/rules/hashlib-insecure-hash-function/ |
| 164 | +.. _S608: https://docs.astral.sh/ruff/rules/hardcoded-sql-expression/ |
| 165 | +.. _S608: https://docs.astral.sh/ruff/rules/hardcoded-sql-expression/ |
0 commit comments