cds-104/notebooks/SQL-Injectionn mit Code.ipynb
2026-04-16 15:15:01 +02:00

278 lines
7.5 KiB
Plaintext

{
"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
}