diff --git a/.gitignore b/.gitignore index e43b0f9..4127086 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .DS_Store +.ipynb_checkpoints \ No newline at end of file diff --git a/notebooks/PostgreSQL-Python mit Code.ipynb b/notebooks/PostgreSQL-Python mit Code.ipynb new file mode 100644 index 0000000..e68010f --- /dev/null +++ b/notebooks/PostgreSQL-Python mit Code.ipynb @@ -0,0 +1,190 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b53d472a-14d4-42bb-a0ee-38eb8c9c24a8", + "metadata": {}, + "source": [ + "Zunächst muss ein Paket zur Anbindung installiert werden. Wir verwenden psycopg 2 (psycopg.org).\n", + "Dies kann über den Reiter \"Environment\" im Anaconda Navicator installiert werden.\n", + "Ist dies geschehen können wir das Paket importieren." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d3fea87-d2a6-4da8-9327-4c08bb70ef9e", + "metadata": {}, + "outputs": [], + "source": [ + "import psycopg2" + ] + }, + { + "cell_type": "markdown", + "id": "bedf4588-60dc-4169-9295-21f6b3317e9f", + "metadata": {}, + "source": [ + "Nun sind wir bereit, um eine Verbindung zur Datenbank aufzubauen. Nehmen wir zum Beispiel die \"bank\" Datenbank. Da wir die Installation local haben, muss keine URL angegeben werden. Dafür legen wir eine Variable mit dem connect Befehl an." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62b5a0b5-bafd-4125-8b62-4a2aa493a061", + "metadata": {}, + "outputs": [], + "source": [ + "conn = psycopg2.connect (\"dbname=bank user=postgres password=postgres\")" + ] + }, + { + "cell_type": "markdown", + "id": "8861806c-5786-42fb-81d3-1ba5283b1d2b", + "metadata": {}, + "source": [ + "Als nächstes führen wir eine einfache SELECT Abfrage aus.\n", + "Zunächst werden wir verbunden, dann stellen wir die Abfrage, dann rufen wir das Ergebnis der Abfrage ab und lassen es uns anzeigen.\n", + "Dazu benötigen wir ein cursor Objekt, das uns die Abfrage aber auch die Rücklieferung der Daten liefert. Dieses kommt in die Variable cursor.\n", + "Die Variable result speichert uns die Ergebnisse. fetchall wartet bis alle Ergebniszeilen geliefert sind und ermöglicht dann die Anzeige." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09dbc41c-0ed7-449a-853d-3a18fbb1d97e", + "metadata": {}, + "outputs": [], + "source": [ + "cursor = conn.cursor()\n", + "cursor.execute(\"SELECT * FROM account;\")\n", + "result = cursor.fetchall()\n", + "result" + ] + }, + { + "cell_type": "markdown", + "id": "81c22552-4d3c-4824-82c7-5b8a0c74402c", + "metadata": {}, + "source": [ + "Pro Klammer bekommen wir nun ein Tupel angezeigt. Das ist noch nicht so schön. Mit einer kleinen Schleife können wir uns die Tupel zeilenweise anzeigen lassen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dba24620-fe85-4feb-8109-59a3d7c5e3b3", + "metadata": {}, + "outputs": [], + "source": [ + "cursor = conn.cursor()\n", + "cursor.execute(\"SELECT * FROM account;\")\n", + "result = cursor.fetchall()\n", + "\n", + "for row in result:\n", + " print(row)" + ] + }, + { + "cell_type": "markdown", + "id": "b975ba44-de7e-4337-a2f9-a4fa06fc59b1", + "metadata": {}, + "source": [ + "Wollen wir nur eine bestimmte Spalte geht dies über die Angabe der Spaltennummer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6159012d-ea9c-44da-bec0-5d073d210bd3", + "metadata": {}, + "outputs": [], + "source": [ + "cursor = conn.cursor()\n", + "cursor.execute(\"SELECT * FROM account;\")\n", + "result = cursor.fetchall()\n", + "\n", + "for row in result:\n", + " print(row[0])" + ] + }, + { + "cell_type": "markdown", + "id": "b3180855-e952-4d4a-86b5-a27c9d326f69", + "metadata": {}, + "source": [ + "Spaltennummern zählen ist nun etwas aufwendig und unschön. Mit einer Erweituerung des Pakets können wir den cursor anpassen und dann auch Spaltennamen angeben. Wir wählen psycopg2.extras und dann einen DictCursor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75b7a5c8-4677-4546-a461-e7b36b97ff5e", + "metadata": {}, + "outputs": [], + "source": [ + "import psycopg2.extras\n", + "cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)\n", + "cursor.execute(\"SELECT * FROM account;\")\n", + "result = cursor.fetchall()\n", + "\n", + "for row in result:\n", + " print(row[0], row['avail_balance'])\n", + "\n", + "# Es können nur auch beide Varianten (Nummer oder Name) verwendet werden." + ] + }, + { + "cell_type": "markdown", + "id": "3b90228d-bbc6-40ca-bf18-abb698318603", + "metadata": {}, + "source": [ + "Problembehandlung Transaktion: Da wir Abfragen durchführen sollten wir diese auch korrekt starten und abschliessen. Vor allem wenn es zu einem Fehler (z.B. einem Tippfehler) kommt. Anosnten laufen wir auf eine Fehlermeldung und eine offen Transaktion.\n", + "Die Lösung ist unseren SQL Befehl in einen try, except bzw finally Block zu setzen.\n", + "MIt conn.commit() wird die Durchführung der Transaktion bestätigt." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e24b6bb-4773-4652-b027-7ee4faf6db92", + "metadata": {}, + "outputs": [], + "source": [ + "cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)\n", + "\n", + "try: \n", + " cursor.execute(\"SELECT * FROM account;\")\n", + " result = cursor.fetchall()\n", + " \n", + " for row in result:\n", + " print(row['avail_balance'])\n", + "\n", + " conn.commit()\n", + "except:\n", + " conn.rollback()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/PostgreSQL-Python.ipynb b/notebooks/PostgreSQL-Python.ipynb new file mode 100644 index 0000000..7c411d8 --- /dev/null +++ b/notebooks/PostgreSQL-Python.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b53d472a-14d4-42bb-a0ee-38eb8c9c24a8", + "metadata": {}, + "source": [ + "Zunächst muss ein Paket zur Anbindung installiert werden. Wir verwenden psycopg 2 (psycopg.org).\n", + "Dies kann über den Reiter \"Environment\" im Anaconda Navicator installiert werden.\n", + "Ist dies geschehen können wir das Paket importieren." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d3fea87-d2a6-4da8-9327-4c08bb70ef9e", + "metadata": {}, + "outputs": [], + "source": [ + "import psycopg2" + ] + }, + { + "cell_type": "markdown", + "id": "bedf4588-60dc-4169-9295-21f6b3317e9f", + "metadata": {}, + "source": [ + "Nun sind wir bereit, um eine Verbindung zur Datenbank aufzubauen. Nehmen wir zum Beispiel die \"bank\" Datenbank. Da wir die Installation local haben, muss keine URL angegeben werden. Dafür legen wir eine Variable mit dem connect Befehl an." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62b5a0b5-bafd-4125-8b62-4a2aa493a061", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "8861806c-5786-42fb-81d3-1ba5283b1d2b", + "metadata": {}, + "source": [ + "Als nächstes führen wir eine einfache SELECT Abfrage aus.\n", + "Zunächst werden wir verbunden, dann stellen wir die Abfrage, dann rufen wir das Ergebnis der Abfrage ab und lassen es uns anzeigen.\n", + "Dazu benötigen wir ein cursor Objekt, das uns die Abfrage aber auch die Rücklieferung der Daten liefert. Dieses kommt in die Variable cursor.\n", + "Die Variable result speichert uns die Ergebnisse. fetchall wartet bis alle Ergebniszeilen geliefert sind und ermöglicht dann die Anzeige." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09dbc41c-0ed7-449a-853d-3a18fbb1d97e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "81c22552-4d3c-4824-82c7-5b8a0c74402c", + "metadata": {}, + "source": [ + "Pro Klammer bekommen wir nun ein Tupel angezeigt. Das ist noch nicht so schön. Mit einer kleinen Schleife können wir uns die Tupel zeilenweise anzeigen lassen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dba24620-fe85-4feb-8109-59a3d7c5e3b3", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "b975ba44-de7e-4337-a2f9-a4fa06fc59b1", + "metadata": {}, + "source": [ + "Wollen wir nur eine bestimmte Spalte geht dies über die Angabe der Spaltennummer." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6159012d-ea9c-44da-bec0-5d073d210bd3", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "b3180855-e952-4d4a-86b5-a27c9d326f69", + "metadata": {}, + "source": [ + "Spaltennummern zählen ist nun etwas aufwendig und unschön. Mit einer Erweituerung des Pakets können wir den cursor anpassen und dann auch Spaltennamen angeben. Wir wählen psycopg2.extras und dann einen DictCursor." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75b7a5c8-4677-4546-a461-e7b36b97ff5e", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "3b90228d-bbc6-40ca-bf18-abb698318603", + "metadata": {}, + "source": [ + "Problembehandlung Transaktion: Da wir Abfragen durchführen sollten wir diese auch korrekt starten und abschliessen. Vor allem wenn es zu einem Fehler (z.B. einem Tippfehler) kommt. Anosnten laufen wir auf eine Fehlermeldung und eine offen Transaktion.\n", + "Die Lösung ist unseren SQL Befehl in einen try, except bzw finally Block zu setzen.\n", + "MIt conn.commit() wird die Durchführung der Transaktion bestätigt." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e24b6bb-4773-4652-b027-7ee4faf6db92", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/Python Wiederholung mit Code.ipynb b/notebooks/Python Wiederholung mit Code.ipynb new file mode 100644 index 0000000..acf1403 --- /dev/null +++ b/notebooks/Python Wiederholung mit Code.ipynb @@ -0,0 +1,397 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python - Kurzwiederholung\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Elementare Datentypen" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# eine Variable mit einem int-Wert\n", + "i = 10\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "123456395823842193412376429385" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Python kann sher grosse Zahlen verarbeiten:\n", + "j = 123456395823842193412376429384\n", + "j+1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# int-Zahlen sind richtige Objekte - sie brauchen mehr Speicher, \n", + "# haben aber auch mehr Fähigkeiten als in anderen Sprachen\n", + "import sys\n", + "\n", + "print(sys.getsizeof(10)) # Specherverbrauch einer einzelnen Zahl\n", + "print(i.bit_length()) # Methoden, hier Bitlänge der Zahl" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ein Float \n", + "f = 5.0\n", + "\n", + "# auch Floats haben Methoden\n", + "print(f.is_integer())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Floats haben so ihre Probleme...\n", + "0.1 + 0.2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Strings, Konkatenation\n", + "s = \"Hello\" + \" \" + \"World\"\n", + "s" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Boolsche Werte\n", + "a = True\n", + "b = False\n", + "\n", + "print(a and b)\n", + "print(a or b)\n", + "type(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Umwandlung von Datentypen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# zahl in string umwandeln\n", + "i = 5\n", + "str(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# string in zahl umwandeln\n", + "s = \"55\"\n", + "float(s)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Kontrollstrukturen: if, while, for, range-Funktion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "i = 10\n", + "\n", + "if i > 5:\n", + " print(\"i ist grösser 5\")\n", + " \n", + "while i > 0:\n", + " print(i)\n", + " i = i - 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for i in range(5):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# rückwärts zählen\n", + "for i in range(10, 4, -1):\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Beispiele für Funktionen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add(i, j):\n", + " return i+j" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(add(2, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Listen, Indizierung, Slicing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Platznummern\n", + "# 0 1 2 3 4 5 6\n", + "l = [1, 2, 3, 4, 5, 6, 7]\n", + "\n", + "# slicing\n", + "l[1::2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# enumerate: Aufzählen einer Liste (Tupelbildung mit Index)\n", + "list(enumerate([5,9,42]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "l = [\"test\", 1, 5.5, True] # Listen können gemischte Werte enthalten" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tupel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = (4, 5) # Tupel einpacken\n", + "a, b = t # Tupel auspacken\n", + "\n", + "print(a)\n", + "print(b)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "builtin-Funktionen, Standardbibliothek" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# builtin-Funktion\n", + "# range, list, int, float, len, sum, bool, tuple " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ein Import - hier math\n", + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "math.exp(2.0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dictionaries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d = { 'eins': 'one', 'zwei': 'two' }\n", + "\n", + "d.keys(), d.values()\n", + "\n", + "for key, value in d.items():\n", + " print(key, '->', value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List-Comprehensions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Quadratzahlen mit gerader Basis\n", + "[ x*x for x in range(0,21) if x % 2 == 0 ]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Statistics" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = [3,4,5,6,7]\n", + "mean(a), variance(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b = [0, 2, 4, 6, 8, 10]\n", + "mean(b), variance(b)" + ] + } + ], + "metadata": { + "interpreter": { + "hash": "a6b707a736c5fbba452b904aff207ddd250a7524df1f8c74db5bc52ff4a2560b" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/Python Wiederholung.ipynb b/notebooks/Python Wiederholung.ipynb new file mode 100644 index 0000000..bfa591a --- /dev/null +++ b/notebooks/Python Wiederholung.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python - Kurzwiederholung\n", + "\n", + "Hier werden wir einige Beispiele betrachten, um noch einmal einige Python-Konzepte zu wiederholen. Sie können mitschreiben, oder am Ende mein fertiges Notebook herunterladen." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Elementare Datentypen" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Umwandlung von Datentypen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Kontrollstrukturen: if, while, for, range-Funktion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Beispiele für Funktionen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Listen, Indizierung, Slicing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tupel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "builtin-Funktionen, Standardbibliothek" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dictionaries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "List-Comprehensions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Statistics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/SQL-Injectionn mit Code.ipynb b/notebooks/SQL-Injectionn mit Code.ipynb new file mode 100644 index 0000000..b3b41fa --- /dev/null +++ b/notebooks/SQL-Injectionn mit Code.ipynb @@ -0,0 +1,277 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SQL - Injection\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Vorbereitung" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# Falls noch nicht geschehen können die Pakte importiert werden\n", + "import psycopg2\n", + "import psycopg2.extras" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# als nächstes bauen wir unsere Verbindung auf, legen eine Tabelle an und füllen diese mit zwei Usern:\n", + "conn = psycopg2.connect (\"dbname=7Wochen user=postgres password=postgres\")\n", + "\n", + "cursor = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor)\n", + "\n", + "cursor.execute(\"\"\"\n", + " DROP TABLE IF EXISTS users;\n", + " CREATE TABLE IF NOT EXISTS users (\n", + " id SERIAL PRIMARY KEY,\n", + " username VARCHAR(255) NOT NULL,\n", + " password VARCHAR(255) NOT NULL\n", + " )\n", + "\"\"\")\n", + "\n", + "cursor.execute(\"INSERT INTO users (username, password) VALUES (%s, %s)\", (\"user1\", \"password1\"))\n", + "cursor.execute(\"INSERT INTO users (username, password) VALUES (%s, %s)\", (\"user2\", \"password2\"))\n", + "conn.commit();" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[RealDictRow([('id', 1), ('username', 'user1'), ('password', 'password1')]),\n", + " RealDictRow([('id', 2), ('username', 'user2'), ('password', 'password2')])]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Kurz zum überprüfen, ob die Tabelle angelegt wurde\n", + "\n", + "cursor.execute(\"SELECT * FROM users;\")\n", + "result = cursor.fetchall()\n", + "result" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Angriffsszenario 1 - direkt Übermittlung von Zugangsdaten" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Login erfolgreich\n" + ] + } + ], + "source": [ + "# gehen wir nun davon aus, dass sich ein User, zum Beispiel über ein Formularfeld anmelden möchte.\n", + "# Und zwar mit den folgenden Zugangsdaten:\n", + "username = \"user1\"\n", + "password = \"password1\"\n", + "\n", + "# Das würde dann so ablaufen:\n", + "try:\n", + " cursor.execute(f\"SELECT * FROM users WHERE username='{username}' AND password='{password}'\")\n", + "# Nun holen wir uns eine Ergebniszeile. Gibt es die waren wir mit unserer Anmeldung erfolgreich. Kommt keine Zeile waren unsere Zugangsdaten falsch.\n", + " user = cursor.fetchone()\n", + "\n", + " if user:\n", + " print(\"Login erfolgreich\")\n", + " else:\n", + " print(\"Login fehlgeschlagen\")\n", + "except Exception as e:\n", + " print(e)\n", + " conn.rollback()\n", + "\n", + "# Wir übergeben also die Zeichenkette aus der Python-Variable direkt an unsere SQL-Datenbank.\n", + "# Ändern wir das Passwort sind wir nicht erfolgreich.\n", + "# Um es schöner zu machen fügen wir noch ein Rollback ein" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Angriffszenario 2 - Übergabe von SQL-Befehlen, um Fehler zu hervorzurufen. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "FEHLER: Zeichenkette in Anführungszeichen nicht abgeschlossen bei »'''«\n", + "LINE 1: SELECT * FROM users WHERE username='user1' AND password='''\n", + " ^\n", + "\n" + ] + } + ], + "source": [ + "# gehen wir nun davon aus, dass ein User SQL-Befehle eingibt. Zunächst nur ein einfaches Anführungszeichen als Passwort.\n", + "# Das Ergebnis ist ein erzeugter SQL-Fehler.\n", + "username = \"user1\"\n", + "password = \"'\"\n", + "\n", + "try:\n", + " cursor.execute(f\"SELECT * FROM users WHERE username='{username}' AND password='{password}'\")\n", + " user = cursor.fetchone()\n", + "\n", + " if user:\n", + " print(\"Login erfolgreich\")\n", + " else:\n", + " print(\"Login fehlgeschlagen\")\n", + "except Exception as e:\n", + " print(e)\n", + " conn.rollback()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Angriffszenario 3 - Übergabe von SQL-Befehlen, um einen erfolgreichen Login zu generieren." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Login erfolgreich\n" + ] + } + ], + "source": [ + "# gehen wir nun davon aus, dass ein User SQL-Befehle eingibt. Diesmal die Übergabe eines echten Befehls.\n", + "# Dieser erzeugt eine wahre Aussage wodurch die Passwortüberprüfung erfolgreich wird.\n", + "username = \"user1\"\n", + "password = \"' OR 1=1 --\"\n", + "\n", + "try:\n", + " cursor.execute(f\"SELECT * FROM users WHERE username='{username}' AND password='{password}'\")\n", + " user = cursor.fetchone()\n", + "\n", + " if user:\n", + " print(\"Login erfolgreich\")\n", + " else:\n", + " print(\"Login fehlgeschlagen\")\n", + "except Exception as e:\n", + " print(e)\n", + " conn.rollback()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Abschliessend noch die Variante mit Platzhaltern, die sicherer wäre." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "FEHLER: Zeichenkette in Anführungszeichen nicht abgeschlossen bei »' OR 1=1 --«\n", + "LINE 1: ...CT * FROM users WHERE username=user1 AND password=' OR 1=1 -...\n", + " ^\n", + "\n" + ] + } + ], + "source": [ + "# hier würde nun die Zeichenkette aus der Passworteingabe übergeben und nicht als String direkt zu SQL-Code werden.\n", + "username = \"user1\"\n", + "password = \"' OR 1=1 --\"\n", + "\n", + "try:\n", + " cursor.execute(f\"SELECT * FROM users WHERE username={username} AND password={password}\")\n", + " user = cursor.fetchone()\n", + "\n", + " if user:\n", + " print(\"Login erfolgreich\")\n", + " else:\n", + " print(\"Login fehlgeschlagen\")\n", + "except Exception as e:\n", + " print(e)\n", + " conn.rollback()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "interpreter": { + "hash": "a6b707a736c5fbba452b904aff207ddd250a7524df1f8c74db5bc52ff4a2560b" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/python_itegration/main.py b/python_itegration/main.py new file mode 100644 index 0000000..26f42a3 --- /dev/null +++ b/python_itegration/main.py @@ -0,0 +1 @@ +#%% \ No newline at end of file