Unsachgemäße Neutralisierung von Spezialelementen in einem SQL-Befehl ('SQL Injection')
Beschreibung
SQL Injection ist eine Schwachstelle, die auftritt, wenn Software einen SQL-Befehl ganz oder teilweise unter Verwendung von extern beeinflussten Eingaben einer vorgelagerten Komponente konstruiert, aber Spezialelemente, die den beabsichtigten SQL-Befehl modifizieren könnten, nicht oder nicht korrekt neutralisiert. Angreifer nutzen dies aus, indem sie bösartigen SQL-Code in Eingabefelder, URL-Parameter, Cookies oder HTTP-Header einfügen, die in Datenbankabfragen eingebunden werden. Dies ermöglicht unbefugten Zugriff auf Datenbankinhalte, Modifikation oder Löschung von Daten, Ausführung administrativer Operationen und in einigen Fällen Befehlsausführung auf dem zugrundeliegenden Betriebssystem. SQL Injection rangiert konstant als eine der gefährlichsten und verbreitetsten Webanwendungs-Schwachstellen.
Risiko
SQL Injection stellt katastrophale Risiken für Datenvertraulichkeit, -integrität und -verfügbarkeit dar. Angreifer können Authentifizierung umgehen, gesamte Datenbankinhalte einschließlich Anmeldedaten und persönlicher Informationen extrahieren, Datensätze modifizieren oder löschen, Privilegien auf Datenbankadministrator-Ebene eskalieren und potenziell Betriebssystembefehle durch Datenbankfunktionen wie xp_cmdshell in SQL Server ausführen. Der Heartland-Payment-Systems-Angriff legte 130 Millionen Kreditkartennummern offen, während der TalkTalk-Angriff 157.000 Kundendatensätze kompromittierte. Die Schwachstelle betrifft jede Anwendung, die SQL-Abfragen aus Benutzereingaben konstruiert, von Webanwendungen über Mobile-Backends bis zu APIs. Laut OWASP teilt SQL Injection die Spitzenposition unter Web-Anwendungs-Sicherheitsrisiken und ist typischerweise eine der ersten Angriffsmethoden, die Kriminelle versuchen.
Lösung
Verwenden Sie ausschließlich parametrisierte Abfragen (Prepared Statements) für alle Datenbankoperationen. Parametrisierte Abfragen trennen SQL-Code von Daten und machen Injection unabhängig vom Eingabeinhalt unmöglich. In Sprachen mit ORM-Frameworks (Entity Framework, Hibernate, SQLAlchemy) verwenden Sie die Query-Builder des ORM anstelle von Roh-SQL. Wenn dynamisches SQL absolut notwendig ist, verwenden Sie strikte Allowlist-Validierung für strukturelle Elemente (Tabellennamen, Spaltennamen, Sortierrichtungen) und ordnungsgemäße Parametrisierung für Werte. Implementieren Sie Least-Privilege für Datenbankkonten - Anwendungskonten sollten nur die für ihre Funktion notwendigen Berechtigungen haben. Setzen Sie Web Application Firewalls als Defense-in-Depth ein, aber verlassen Sie sich niemals auf sie als primäre Verteidigung.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Angreifer können gesamte Datenbankinhalte einschließlich Benutzeranmeldedaten, persönlicher Informationen, Finanzdaten und proprietärer Geschäftsinformationen durch UNION-basierte oder Blind-SQL-Injection-Techniken extrahieren. |
| Integrität | Bereich: Integrität SQL Injection ermöglicht das Einfügen, Modifizieren oder Löschen von Datenbankeinträgen. Angreifer können Preise modifizieren, Kontostände ändern, Benutzerrechte ändern oder kritische Daten beschädigen. |
| Verfügbarkeit | Bereich: Verfügbarkeit Angreifer können Tabellen löschen, Datenbanken beschädigen, ressourcenintensive Abfragen ausführen, die Denial-of-Service verursachen, oder Ransomware über Datenbankserverzugriff einsetzen. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle, Vollständige Kompromittierung Authentifizierungsumgehung, Privilegieneskalation zum DBA und potenzielle OS-Befehlsausführung durch Datenbankfunktionen können zu vollständiger Systemkompromittierung führen. |
Beispielcode + Lösungscode
Anfälliger Code
import sqlite3
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form['username']
password = request.form['password']
# ANFÄLLIG: String-Verkettung in SQL-Abfrage
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# Angreifer-Eingabe: username=' OR '1'='1'-- password=beliebig
# Ergibt: SELECT * FROM users WHERE username='' OR '1'='1'--' AND password='beliebig'
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
user = cursor.fetchone()
if user:
return "Login erfolgreich"
return "Ungültige Anmeldedaten"
@app.route('/search')
def search():
product = request.args.get('product')
conn = sqlite3.connect('products.db')
cursor = conn.cursor()
# ANFÄLLIG: Benutzereingabe direkt in Abfrage
# Angriff: product='; DROP TABLE products;--
cursor.execute(f"SELECT * FROM products WHERE name LIKE '%{product}%'")
return str(cursor.fetchall())
Korrigierter Code
import sqlite3
from flask import Flask, request, abort
import re
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
username = request.form.get('username', '')
password = request.form.get('password', '')
# Eingabevalidierung (Defense-in-Depth, nicht primäre Verteidigung)
if not username or not password:
abort(400, 'Fehlende Anmeldedaten')
conn = sqlite3.connect('users.db')
cursor = conn.cursor()
# SICHER: Parametrisierte Abfrage - SQL und Daten sind getrennt
# Die ?-Platzhalter werden durch ordnungsgemäß escapte Werte ersetzt
query = "SELECT * FROM users WHERE username = ? AND password = ?"
cursor.execute(query, (username, password))
user = cursor.fetchone()
conn.close()
if user:
return "Login erfolgreich"
return "Ungültige Anmeldedaten", 401
@app.route('/search')
def search():
product = request.args.get('product', '')
# Eingabelänge validieren
if len(product) > 100:
abort(400, 'Suchbegriff zu lang')
conn = sqlite3.connect('products.db')
cursor = conn.cursor()
# SICHER: Parametrisierte Abfrage mit LIKE
# Die %-Wildcards sind Teil des Parameterwerts, nicht der Abfragestruktur
search_term = f'%{product}%'
cursor.execute("SELECT * FROM products WHERE name LIKE ?", (search_term,))
results = cursor.fetchall()
conn.close()
return str(results)
@app.route('/sort')
def sort_products():
# Für dynamische Tabellen-/Spaltennamen Allowlist-Validierung verwenden
sort_column = request.args.get('sort', 'name')
sort_direction = request.args.get('dir', 'ASC')
# Allowlist-Validierung für strukturelle Elemente
allowed_columns = ['name', 'price', 'date_added']
allowed_directions = ['ASC', 'DESC']
if sort_column not in allowed_columns:
sort_column = 'name'
if sort_direction.upper() not in allowed_directions:
sort_direction = 'ASC'
conn = sqlite3.connect('products.db')
cursor = conn.cursor()
# Sicher, weil Spalte/Richtung aus Allowlist
query = f"SELECT * FROM products ORDER BY {sort_column} {sort_direction}"
cursor.execute(query)
results = cursor.fetchall()
conn.close()
return str(results)
Der korrigierte Code verwendet parametrisierte Abfragen, bei denen ?-Platzhalter durch ordnungsgemäß escapte Werte ersetzt werden, was Injection unmöglich macht. Für strukturelle Elemente wie Spaltennamen, die nicht parametrisiert werden können, stellt strikte Allowlist-Validierung sicher, dass nur bekannt sichere Werte verwendet werden.
Ausgenutzt in der Praxis
Heartland Payment Systems (Zahlungsbranche, 2008)
SQL Injection wurde verwendet, um Heartland Payment Systems zu kompromittieren, einen der größten Zahlungsprozessoren in den USA. Angreifer unter Führung von Albert Gonzalez kompromittierten etwa 130 Millionen Kredit- und Debitkartennummern, mit Gesamtverlusten von geschätzten 300 Millionen Dollar bei betroffenen Finanzinstituten. Gonzalez wurde zu 20 Jahren Gefängnis verurteilt für das, was damals die größte Datenpanne in der US-Geschichte war.
- https://news.sophos.com/en-us/2018/02/19/hackers-sentenced-for-sql-injections-that-cost-300-million/
Sony PlayStation Network (Sony, 2011)
SQL-Injection-Angriffe gegen Sonys PlayStation Network und verwandte Dienste kompromittierten etwa 77 Millionen Benutzerkonten und legten persönliche Informationen einschließlich Namen, Adressen, E-Mail-Adressen, Geburtsdaten, Passwörter und potenziell Kreditkartendaten offen. Der Angriff kostete Sony geschätzte 170 Millionen Dollar und führte zu einem einmonatigen Dienstausfall, der Millionen von Spielern weltweit betraf.
TalkTalk-Datenpanne (TalkTalk, 2015)
Ein SQL-Injection-Angriff auf das britische Telekommunikationsunternehmen TalkTalk kompromittierte persönliche Daten von 156.959 Kunden. Der Angriff nutzte eine Schwachstelle in einem Legacy-Webportal aus und führte zum Diebstahl von Namen, Adressen, Geburtsdaten, Telefonnummern, E-Mail-Adressen und in einigen Fällen Finanzinformationen. TalkTalk wurde vom ICO mit 400.000 Pfund Strafe belegt und hatte Kosten von über 77 Millionen Pfund.
Tools zum Testen/Ausnutzen
-
SQLMap — automatisiertes SQL-Injection-Erkennungs- und Ausnutzungstool, das mehrere Datenbankplattformen unterstützt, mit Fähigkeiten zur Datenextraktion, Datenbank-Fingerprinting und OS-Befehlsausführung durch Datenbankfunktionen.
-
Burp Suite — Web-Sicherheitstestplattform mit SQL-Injection-Scanning, manuellen Testfähigkeiten und Payload-Anpassung für verschiedene Datenbanktypen.
-
jSQL Injection — Java-basiertes SQL-Injection-Tool mit automatischer Datenbankerkennung und mehreren Injection-Techniken einschließlich fehlerbasierter, blinder und zeitbasierter.
CVE-Beispiele
-
CVE-2017-5638 — Apache Struts-Schwachstelle (Equifax-Angriff) ermöglicht SQL-Injection durch Content-Type-Header-Manipulation.
-
CVE-2023-34362 — MOVEit Transfer SQL-Injection führt zu Authentifizierungsumgehung und Datendiebstahl bei Tausenden von Organisationen.
-
CVE-2023-22518 — Atlassian Confluence SQL-Injection ermöglicht unbefugten Datenbankzugriff.
-
CVE-2024-23897 — Jenkins beliebiges Lesen von Dateien führt zu Anmeldedatendiebstahl und nachfolgenden SQL-Injection-Angriffen.
Referenzen
-
MITRE. "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')." https://cwe.mitre.org/data/definitions/89.html
-
OWASP. "SQL Injection." https://owasp.org/www-community/attacks/SQL_Injection
-
OWASP. "SQL Injection Prevention Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
-
PortSwigger. "SQL injection." Web Security Academy. https://portswigger.net/web-security/sql-injection