Datenbank-Sicherheit: SQL Server, MySQL und PostgreSQL absichern
Praxisguide zur Datenbank-Sicherheit: Härtung von SQL Server, MySQL und PostgreSQL, Zugriffscontrolle und Least Privilege, Audit-Logging, Verschlüsselung at rest und in transit, SQL-Injection-Schutz und Datenbank-Monitoring. Mit konkreten SQL-Befehlen und Konfigurationsbeispielen.
Inhaltsverzeichnis (6 Abschnitte)
Datenbanken sind das wertvollste Ziel in jedem Unternehmen: Kundendaten, Finanzdaten, Passwort-Hashes, Geschäftsgeheimnisse. Gleichzeitig sind Datenbanken häufig schlecht gesichert - Default-Konfigurationen, zu weitreichende Berechtigungen und fehlende Verschlüsselung sind die Norm. Dieser Guide zeigt die wichtigsten Sicherheitsmaßnahmen für die drei verbreitetsten Datenbanksysteme.
Häufige Datenbank-Sicherheitsprobleme
Typische Findings in DB-Sicherheitsassessments:
Authentifizierung:
□ Root/SA-Account aktiv und erreichbar
□ Schwache Default-Passwörter (root/root, sa/password)
□ Passwörter in Klartext in Config-Dateien
□ Shared Credentials: alle Anwendungen nutzen denselben DB-User
□ Keine MFA für administrative Datenbankzugänge
Autorisierung:
□ Anwendungsbenutzer mit GRANT ALL oder DBA-Rechten
□ Kein Schema-Level-Locking: App liest Tabellen die sie nicht braucht
□ Öffentlich zugänglicher DB-Port (3306, 5432, 1433 direkt aus Internet!)
Verschlüsselung:
□ Keine TLS für Verbindungen (Klartext-Übertragung!)
□ Keine Verschlüsselung at rest (Festplatten-Diebstahl = Datenverlust)
□ Passwörter als MD5 oder SHA1 gespeichert (nicht gesalzen!)
Logging:
□ Kein Audit-Log: wer hat welche Daten abgefragt?
□ Keine Erkennung von Datenbankdumps (SELECT * FROM kunden WHERE 1=1)
□ Logs werden nicht zentral gespeichert (SIEM-Integration fehlt)
Patchmanagement:
□ Veraltete Datenbankversionen mit bekannten CVEs
□ Kein Patching-Prozess für Datenbankserver
PostgreSQL Härtung
Datei: postgresql.conf
# Verbindungen einschränken:
listen_addresses = '127.0.0.1' # Nur localhost! Kein 0.0.0.0!
port = 5432
max_connections = 100
# SSL erzwingen:
ssl = on
ssl_cert_file = '/etc/postgresql/server.crt'
ssl_key_file = '/etc/postgresql/server.key'
ssl_min_protocol_version = 'TLSv1.2'
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
# Logging (für Audit):
log_connections = on
log_disconnections = on
log_duration = on
log_statement = 'ddl' # DDL-Statements loggen (CREATE/DROP/ALTER)
log_min_duration_statement = 1000 # Queries > 1s loggen (langsame Queries)
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_destination = 'csvlog'
logging_collector = on
---
Datei: pg_hba.conf (Client-Authentifizierung):
# Nur spezifische Hosts dürfen sich verbinden:
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer # Nur OS-User "postgres"
host myapp myappuser 10.0.1.0/24 scram-sha-256 # App-Server-IP
host all all 0.0.0.0/0 reject # Alle anderen: BLOCKIERT
---
Benutzer und Berechtigungen:
-- Root-Zugriff entziehen (postgres-User nur lokal):
REVOKE CONNECT ON DATABASE myapp FROM PUBLIC;
-- Anwendungsbenutzer mit minimalen Rechten:
CREATE USER myapp_user WITH PASSWORD 'StarkesPW123!';
GRANT CONNECT ON DATABASE myapp TO myapp_user;
GRANT USAGE ON SCHEMA public TO myapp_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO myapp_user;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO myapp_user;
-- KEIN: GRANT ALL PRIVILEGES ON DATABASE myapp TO myapp_user;
-- KEIN: GRANT SUPERUSER TO myapp_user;
-- Read-Only-User für Reporting:
CREATE USER reporting_user WITH PASSWORD 'ReadOnly456!';
GRANT CONNECT ON DATABASE myapp TO reporting_user;
GRANT USAGE ON SCHEMA public TO reporting_user;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporting_user;
-- Row-Level Security (RLS) für Multi-Tenant:
ALTER TABLE kunden ENABLE ROW LEVEL SECURITY;
CREATE POLICY kunden_tenant_policy ON kunden
USING (tenant_id = current_setting('app.tenant_id')::INT);
---
Passwort-Hashing in PostgreSQL:
-- FALSCH: MD5 (Standard in alten Versionen):
-- CREATE USER user WITH PASSWORD 'pw' ENCRYPTED; -- erzeugt MD5!
-- RICHTIG: scram-sha-256 (Standard seit PostgreSQL 10):
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
-- Dann alle Passwörter neu setzen!
MySQL/MariaDB Härtung
Initiale Härtung mit mysql_secure_installation:
mysql_secure_installation
→ Root-Passwort setzen: JA
→ Anonymous Users entfernen: JA
→ Remote Root Login deaktivieren: JA
→ Test-Datenbank entfernen: JA
→ Privileges neu laden: JA
/etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
# Netzwerk:
bind-address = 127.0.0.1 # Kein Remote-Zugriff!
skip-networking = 0 # Lokales Socket ok
port = 3306
# Sicherheit:
local-infile = 0 # LOAD DATA LOCAL INFILE deaktivieren
skip-symbolic-links # Symlink-Angriffe verhindern
secure-file-priv = /var/lib/mysql-files # Dateizugriff einschränken
sql_mode = "STRICT_ALL_TABLES,NO_AUTO_CREATE_USER"
# SSL:
ssl-ca = /etc/mysql/ca.pem
ssl-cert = /etc/mysql/server-cert.pem
ssl-key = /etc/mysql/server-key.pem
require_secure_transport = ON # SSL PFLICHT für alle Verbindungen!
# Logging:
general_log = OFF # Alle Queries loggen (viel IO!)
general_log_file = /var/log/mysql/general.log
log_error = /var/log/mysql/error.log
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 2
---
Benutzer-Härtung:
-- Unnötige Users entfernen:
SELECT user, host FROM mysql.user;
DROP USER IF EXISTS ''@'localhost'; -- Anonymous User
DROP USER IF EXISTS ''@'hostname'; -- Anonymous User
DROP USER IF EXISTS 'root'@'%'; -- Remote Root VERBIETEN!
-- Root nur lokal erlaubt:
UPDATE mysql.user SET host='localhost' WHERE user='root';
FLUSH PRIVILEGES;
-- Anwendungsbenutzer:
CREATE USER 'webapp'@'10.0.1.%' IDENTIFIED BY 'StarkesPW!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'webapp'@'10.0.1.%';
-- KEIN: GRANT ALL ON *.* TO 'webapp';
-- Plugin für Passwort-Policy:
INSTALL PLUGIN validate_password SONAME 'validate_password.so';
SET GLOBAL validate_password_policy=STRONG;
SET GLOBAL validate_password_length=12;
SET GLOBAL validate_password_mixed_case_count=1;
SET GLOBAL validate_password_special_char_count=1;
-- Audit-Logging (MariaDB Audit Plugin):
INSTALL PLUGIN server_audit SONAME 'server_audit';
SET GLOBAL server_audit_logging=ON;
SET GLOBAL server_audit_events='CONNECT,QUERY_DDL';
Microsoft SQL Server Härtung
Grundlegende Härtungsmaßnahmen:
-- SA-Account deaktivieren (falls Windows Auth genutzt):
ALTER LOGIN sa DISABLE;
-- Oder: starkes Passwort setzen + umbenennen:
ALTER LOGIN sa WITH NAME = [sqlbackup_only];
ALTER LOGIN sqlbackup_only WITH PASSWORD = 'StarkesLangesPasswort!2024';
-- Nur Windows Authentication (keine SQL Authentication):
-- SSMS: Server Properties → Security → Windows Authentication Mode
-- xp_cmdshell deaktivieren (OS-Befehle über SQL!):
EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;
-- Remote-Verbindungen einschränken (nur spezifische IPs):
-- SQL Server Configuration Manager → SQL Server Network Configuration
-- → TCP/IP Properties → IP Addresses → Specific IPs konfigurieren
-- Transparent Data Encryption (TDE) aktivieren:
-- Datenbankdateien auf Festplatte verschlüsselt:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'Verschlüsselungspasswort!';
CREATE CERTIFICATE ServerCert WITH SUBJECT = 'TDE Certificate';
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE ServerCert;
ALTER DATABASE MyDatabase SET ENCRYPTION ON;
---
Least Privilege für Anwendungsbenutzer:
-- Neuen Login erstellen:
CREATE LOGIN AppUser WITH PASSWORD = 'SicheresPasswort123!';
-- Nur auf spezifische Datenbank:
USE MyDatabase;
CREATE USER AppUser FOR LOGIN AppUser;
-- Nur nötige Schema-Rechte:
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo TO AppUser;
DENY EXECUTE ON xp_cmdshell TO AppUser; -- Extra absichern!
-- KEIN: GRANT CONTROL ON DATABASE TO AppUser;
-- KEIN: Membership in db_owner!
---
SQL Server Audit:
CREATE SERVER AUDIT MyAudit
TO FILE (FILEPATH = 'C:\SQLAudit\');
CREATE DATABASE AUDIT SPECIFICATION MyDBSpec
FOR SERVER AUDIT MyAudit
ADD (SELECT, INSERT, UPDATE, DELETE ON SCHEMA::dbo BY public);
ALTER SERVER AUDIT MyAudit WITH (STATE = ON);
ALTER DATABASE AUDIT SPECIFICATION MyDBSpec WITH (STATE = ON);
SQL Injection Prevention - Code-Level
SQL Injection ist die #1 Datenbankbedrohung (OWASP A03:2021)
FALSCH - String-Konkatenation:
# Python (unsicher!):
query = "SELECT * FROM users WHERE name = '" + user_input + "'"
cursor.execute(query)
# Angreifer: user_input = "' OR '1'='1"
# → Query: SELECT * FROM users WHERE name = '' OR '1'='1'
# → Alle User werden zurückgegeben!
RICHTIG - Prepared Statements:
# Python (sicher!):
query = "SELECT * FROM users WHERE name = %s"
cursor.execute(query, (user_input,))
# Java JDBC:
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE name = ?"
);
stmt.setString(1, userName);
# Node.js mit pg (PostgreSQL):
const result = await client.query(
'SELECT * FROM users WHERE name = $1',
[userName]
);
# PHP PDO:
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute(['name' => $userName]);
ORM als Zusatzschutz:
→ Prisma, Sequelize, Hibernate, Entity Framework
→ ORMs generieren Prepared Statements automatisch
→ ABER: Raw Queries in ORM können noch anfällig sein!
→ Hibernate: session.createQuery("... WHERE id = :id").setParameter("id", id)
Stored Procedures (wenn parametrisiert):
CREATE PROCEDURE GetUser @UserName NVARCHAR(50)
AS
BEGIN
SELECT * FROM Users WHERE Name = @UserName;
END;
-- KEIN dynamisches SQL im SP: EXEC('SELECT... ' + @param) → unsicher!
Input-Validierung als zweite Linie:
→ Typ-Prüfung: ist ID wirklich eine Zahl? int(user_id)
→ Whitelist: nur erlaubte Zeichen akzeptieren
→ Länge begrenzen: max 255 Zeichen für Strings
→ KEINE Blacklist! Angreifer finden immer Wege um sie zu umgehen
Datenbank-Monitoring und Audit
Was muss überwacht werden?
□ Alle Logins (Erfolg + Fehler)
□ Privilegierte Aktionen (GRANT, DROP, ALTER)
□ Datenzugriffe auf sensitive Tabellen (Kunden, Finanzen, Passwörter)
□ Massenabfragen: "SELECT * WHERE 1=1" → möglicher Dump!
□ Verbindungen von ungewöhnlichen IPs
□ Außerhalb der Geschäftszeiten aktive Verbindungen
□ Schema-Änderungen (CREATE TABLE, ALTER TABLE)
SIEM-Integration:
Filebeat → Elasticsearch (für MySQL-Logs):
filebeat.inputs:
- type: log
paths:
- /var/log/mysql/general.log
- /var/log/mysql/error.log
fields:
source: mysql
env: production
Alert bei verdächtigen Queries (Elasticsearch KQL):
message: *SELECT * FROM* AND message: *WHERE 1=1*
→ Möglicher Datenbankdump!
Database Activity Monitoring (DAM) Tools:
→ IBM Guardium: Enterprise DAM
→ Imperva Database Security: umfassendes Monitoring
→ pgAudit: Open Source für PostgreSQL
→ MySQL Enterprise Audit: kommerziell
DAM-Features:
→ Real-Time-Erkennung von SQL-Injection-Mustern
→ Verhaltensbaseline: normaler Query-Traffic vs. Anomalie
→ Automatisches Blockieren bei erkanntem Angriff (optional)
→ DSGVO-konforme Protokollierung (wer, was, wann)
Backup-Sicherheit:
□ Backups verschlüsselt? (mysqldump | gpg -e > backup.sql.gpg)
□ Backup-Server: getrennt vom Produktionsnetz
□ Backup-Zugriff: eigener User mit minimalen Rechten
□ Restore-Test: monatlich (können wir wirklich wiederherstellen?)
□ Backup-Retention: wie lange? (DSGVO: nicht länger als nötig!) Fragen zu diesem Thema?
Unsere Experten beraten Sie kostenlos und unverbindlich.
Über den Autor
Geschäftsführender Gesellschafter der AWARE7 GmbH mit langjähriger Expertise in Informationssicherheit, Penetrationstesting und IT-Risikomanagement. Absolvent des Masterstudiengangs Internet-Sicherheit an der Westfälischen Hochschule (if(is), Prof. Norbert Pohlmann). Bestseller-Autor im Wiley-VCH Verlag und Lehrbeauftragter der ASW-Akademie. Einschätzungen zu Cybersecurity und digitaler Souveränität erschienen u.a. in Welt am Sonntag, WDR, Deutschlandfunk und Handelsblatt.
10 Publikationen
- Einsatz von elektronischer Verschlüsselung - Hemmnisse für die Wirtschaft (2018)
- Kompass IT-Verschlüsselung - Orientierungshilfen für KMU (2018)
- IT Security Day 2025 - Live Hacking: KI in der Cybersicherheit (2025)
- Live Hacking - Credential Stuffing: Finanzrisiken jenseits Ransomware (2025)
- Keynote: Live Hacking Show - Ein Blick in die Welt der Cyberkriminalität (2025)
- Analyse von Angriffsflächen bei Shared-Hosting-Anbietern (2024)
- Gänsehaut garantiert: Die schaurigsten Funde aus dem Leben eines Pentesters (2022)
- IT Security Zertifizierungen — CISSP, T.I.S.P. & Co (Live-Webinar) (2023)
- Sicherheitsforum Online-Banking — Live Hacking (2021)
- Nipster im Netz und das Ende der Kreidezeit (2017)