Also, erstmal schauen wir uns an, was wir eigentlich schützen – oder besser gesagt: vor wem. Am Anfang dieses Levels haben wir schon mal SQL-Injektionen erwähnt, eine der beliebtesten und zerstörerischsten Angriffsarten auf Datenbanken. Der Angriff läuft so: Ein Angreifer schickt bösartigen SQL-Code in deine Query, um sie zu "verarschen" und Zugriff auf Daten zu bekommen, die er eigentlich nicht sehen dürfte. Jetzt schauen wir uns das genauer an.
Beispiel für eine SQL-Injektion
Stell dir vor, du hast eine Web-App mit einem einfachen Feld für Benutzername und Passwort. Das Backend macht eine SQL-Query, um zu checken, ob der User in der Datenbank ist:
SELECT * FROM users WHERE username = 'admin' AND password = 'password123';
Sieht erstmal harmlos aus... solange der User korrekte Daten eingibt. Aber was passiert, wenn jemand Folgendes eingibt:
- Benutzername:
admin' -- - Passwort: (lassen wir leer)
Am Ende wird die Query zu sowas wie:
SELECT * FROM users WHERE username = 'admin' -- AND password = 'password123';
Achte auf die -- Zeichen, die in SQL einen Kommentar einleiten. Alles danach wird ignoriert. Das Passwort wird also gar nicht mehr geprüft und der Angreifer kommt als Admin rein!
Potenzielle Folgen von SQL-Injektionen
SQL-Injektionen können richtig üble Folgen haben:
- Unbefugter Zugriff auf Daten. Zum Beispiel kann ein Angreifer an vertrauliche Sachen wie User-Passwörter kommen.
- Löschen oder Verändern von Daten. Jemand könnte die ganze Tabelle löschen oder Chaos anrichten.
- Ausführen von beliebigem SQL-Code. Stell dir vor, jemand führt
DROP DATABASEaus... Ja, das ist ein Albtraum.
Aber wir lassen uns nicht einschüchtern! PostgreSQL gibt uns ein paar Tools an die Hand, mit denen wir uns gegen solche Angriffe schützen können.
Wie schützt man sich? Methoden zur Vermeidung von SQL-Injektionen
- Verwendung von Prepared Statements (
PREPAREundEXECUTE)
Prepared Statements sind wie ein erprobtes Rezept für deinen SQL-Code. Sie funktionieren so: Du "bereitest" die SQL-Query einmal vor und gibst die Daten später extra rein. Dadurch kann kein böser Code eingeschleust werden.
Hier ein Beispiel, wie es richtig geht:
Bereite die Query mit PREPARE vor.
PREPARE user_login (text, text) AS
SELECT *
FROM users
WHERE username = $1 AND password = $2;
Die Query mit zwei Parametern $1 und $2 wartet darauf, dass du später echte Werte übergibst.
Nutze EXECUTE, um die Query auszuführen.
EXECUTE user_login('admin', 'password123');
PostgreSQL escaped dabei automatisch alle Userdaten und verhindert so das Einschleusen von bösem SQL-Code.
Vorteile von diesem Ansatz:
- SQL-Injektionen sind unmöglich, weil die Parameter als reine Daten behandelt werden, nicht als Teil des SQL-Codes.
- Queries werden sicherer und laufen schneller, weil der Ausführungsplan gecached wird.
- Parameterisierte Queries (Parameterized Queries)
Diese Methode ist besonders beliebt in Apps, die mit Programmiersprachen wie Python oder Java geschrieben sind. Anstatt PREPARE und EXECUTE selbst zu nutzen, kannst du Libraries oder ORMs nehmen, die die Parameter automatisch behandeln.
Beispiel mit Python und der psycopg2 Library:
import psycopg2
connection = psycopg2.connect(
dbname="your_db",
user="your_user",
password="your_password",
host="localhost",
port="5432"
)
cursor = connection.cursor()
# Verwendung einer parameterisierten Query
username = "admin"
password = "password123"
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))
# Deine Daten sind komplett sicher!
result = cursor.fetchall()
print(result)
Achte auf das %s in der SQL-Query – das ist die Stelle, wo der Parameter reinkommt. Die psycopg2 Library kümmert sich um die sichere Übergabe der Daten.
- Validierung der Eingabedaten
Wenn du Daten vom User bekommst, check, ob sie deinen Erwartungen entsprechen. Zum Beispiel:
- Für Textdaten nutze Regular Expressions, um sicherzugehen, dass keine verbotenen Zeichen drin sind.
- Für Zahlen prüfe, ob es wirklich Zahlen sind.
Beispiel in Python:
import re
username = input("Gib den Benutzernamen ein: ")
# Erlaubt sind nur Buchstaben, Zahlen und Unterstriche
if re.match(r"^\w+$", username):
print("Benutzername ist korrekt")
else:
print("Gefährlicher Benutzername!")
- Verwendung minimaler Rechte
Sorge dafür, dass die Rollen, mit denen Queries ausgeführt werden, nur die nötigsten Rechte haben. Gib zum Beispiel keine Rechte für DROP TABLE oder ALTER TABLE, wenn das nicht gebraucht wird.
- Logging von verdächtigen Aktionen
Du kannst PostgreSQL-Parameter nutzen, um die User-Aktivität zu überwachen:
log_statement = 'all'– loggt alle Queries.log_connections = on– loggt alle Verbindungen zur Datenbank.
Diese Einstellungen helfen dir, potenziell schädliche Aktionen zu erkennen.
Beispiele für die Umsetzung
Beispiel 1: Verwendung eines Prepared Statements in SQL
-- Wir erstellen ein Prepared Statement
PREPARE check_credentials (text, text) AS
SELECT * FROM users WHERE username = $1 AND password = $2;
-- Wir führen die Query mit sicheren Parametern aus
EXECUTE check_credentials('admin', 'password123');
Beispiel 2: Parameterisierte Query in Python
query = "UPDATE users SET last_login = NOW() WHERE username = %s"
username = "admin"
cursor.execute(query, (username,))
Sicherheitsempfehlungen
Prüfe immer die Eingabedaten. Vertraue niemals Daten, die vom User kommen.
Nutze nur Prepared Statements oder parameterisierte Queries. Diese Methoden sind dein Hauptschutz gegen SQL-Injektionen.
Vergib Rollen nur mit den minimal nötigen Rechten. So minimierst du den Schaden, falls ein Angreifer Zugriff bekommt.
Richte Logging ein und prüfe regelmäßig die Logs. So bleibst du über die Aktivitäten in deiner Datenbank im Bilde.
SQL-Injektionen sind echt ein fieses Biest, aber mit Prepared Statements, parameterisierten Queries und guten Praktiken schützt du deine Datenbank und kannst nachts ruhig schlafen, ohne Angst, dass jemand "aus Versehen" alle deine Tabellen löscht. PostgreSQL gibt dir alle Tools dafür – also, leg los!
GO TO FULL VERSION