TL;DR
Unternehmen sichern ihre wertvollsten
Diese Zusammenfassung wurde KI-gestützt erstellt (EU AI Act Art. 52).
Inhaltsverzeichnis (6 Abschnitte)
Die Datenbank ist das Herzstück der meisten Anwendungen - und oft das schwächste Glied. Standardinstallationen sind auf Komfort optimiert, nicht auf Sicherheit: SA-Account mit leerem Passwort, pg_hba.conf die alle Verbindungen erlaubt, keine Audit-Logs. Ein Angreifer der Datenbankzugang erlangt, hat in der Regel das Spiel gewonnen.
Häufige Datenbank-Schwachstellen
Top-Schwachstellen in Datenbankumgebungen:
1. Standard-Credentials (häufigste Schwachstelle!):
→ MySQL root ohne Passwort (Standard bei vielen Installationen)
→ MSSQL SA-Account mit "sa" als Passwort
→ PostgreSQL postgres-User ohne Passwort-Authentifizierung
→ Oracle SYS/SYSTEM mit Standard-Passwörtern
2. Überprivilegierte Accounts:
→ Anwendungs-User hat DBA-Rechte (braucht nur SELECT/INSERT/UPDATE!)
→ Entwickler-Accounts mit Production-Zugang
→ Shared Accounts: alle Entwickler nutzen denselben DB-User
3. Netzwerk-Exposition:
→ Port 5432 (PostgreSQL), 3306 (MySQL), 1433 (MSSQL) direkt aus Internet
→ Firewall-Regel: ANY → DB-Server → ALLOW
→ Kein VPN/Bastion-Host für DB-Administration
4. Fehlende Verschlüsselung:
→ Keine TLS-Verbindung zwischen App und DB
→ Sensitive Daten unverschlüsselt (Passwörter im Klartext!)
→ Backups unverschlüsselt
5. Kein Audit-Logging:
→ Welcher Nutzer hat wann welche Daten abgefragt? → Unbekannt
→ Datenschutzvorfall: keine forensische Spur möglich
→ DSGVO: Nachweispflicht bei Data Breach kaum erfüllbar
SQL-Injection (OWASP #3):
→ Benutzer-Input direkt in SQL-Query eingebaut
→ Angreifer: admin'-- → überspringt WHERE-Klausel
→ Oder: UNION SELECT password FROM users
→ Lösung: Prepared Statements IMMER, String-Konkatenation NIE
PostgreSQL Härtung
PostgreSQL: Von der Installation zur sicheren Konfiguration
1. pg_hba.conf - Verbindungsauthentifizierung:
Standard (gefährlich!):
# TYPE DATABASE USER ADDRESS METHOD
local all all peer
host all all 127.0.0.1 md5
host all all ::1/128 md5
Gehärtet:
# Lokale Verbindungen: nur für PostgreSQL-Admin
local all postgres peer
# Alle anderen lokalen: scram-sha-256 (md5 ist schwach!)
local all all scram-sha-256
# Netzwerk: nur aus App-Subnet, spezifische DBs
host myapp appuser 10.0.1.0/24 scram-sha-256
# Keine Verbindung von außerhalb (kein 0.0.0.0/0!)
# PostgreSQL 14+: scram-sha-256 ist Standard
2. postgresql.conf Härtung:
# Nur auf benötigten Interfaces lauschen (nicht 0.0.0.0!)
listen_addresses = 'localhost,10.0.2.5' # Nur Loopback + DB-NIC
# SSL erzwingen:
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_min_protocol_version = 'TLSv1.2'
# Log-Konfiguration für Audit:
log_connections = on
log_disconnections = on
log_duration = off # nur bei Performance-Debugging einschalten!
log_min_duration_statement = 1000 # Slow Queries > 1s loggen
log_line_prefix = '%t [%p]: user=%u,db=%d,app=%a,client=%h '
log_statement = 'ddl' # alle DDL-Statements loggen (CREATE, DROP, ALTER)
3. Least Privilege Rollen:
-- Anwendungs-User: nur DML, kein DDL, keine pg_catalog-Rechte
CREATE USER appuser WITH PASSWORD 'StarkesPasswort123!';
GRANT CONNECT ON DATABASE myapp TO appuser;
GRANT USAGE ON SCHEMA public TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO appuser;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO appuser;
-- Read-Only User für Reporting:
CREATE USER reporting WITH PASSWORD 'AndersStarkesPasswort!';
GRANT CONNECT ON DATABASE myapp TO reporting;
GRANT USAGE ON SCHEMA public TO reporting;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reporting;
-- KEIN Zugang zu postgresql-spezifischen Systemkatalogen:
REVOKE ALL ON SCHEMA information_schema FROM appuser;
4. Row Level Security (RLS) für Multi-Tenant:
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::INTEGER);
-- App setzt: SET app.tenant_id = '42';
-- Dann sieht User nur Zeilen mit tenant_id = 42!
5. pgAudit Extension (Enterprise-Audit):
CREATE EXTENSION pgaudit;
# postgresql.conf:
pgaudit.log = 'write, function, role, ddl, misc'
pgaudit.log_catalog = off # Kein Log für pg_catalog (zu viel Noise)
# → Loggt: welcher User hat wann welche Tabellen modifiziert
MySQL / MariaDB Härtung
MySQL: Sicheres Setup
1. mysql_secure_installation ausführen:
sudo mysql_secure_installation
→ Root-Passwort setzen
→ Anonymous Users entfernen
→ Remote Root-Login deaktivieren
→ Test-Datenbank entfernen
2. Root-Zugang einschränken:
-- Root nur von localhost (NICHT von außen!)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'SehrStarkesRootPasswort!';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
FLUSH PRIVILEGES;
-- Kein Zugang von '%' (alle Hosts) für Admin-Accounts!
SELECT User, Host FROM mysql.user;
3. Anwendungs-User:
-- Anwendungs-User nur mit notwendigen Rechten:
CREATE USER 'appuser'@'10.0.1.%' IDENTIFIED BY 'AppPasswort!';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'appuser'@'10.0.1.%';
-- KEIN GRANT OPTION (kann keine weiteren Rechte vergeben!)
-- KEIN FILE, PROCESS, SUPER (System-Privileges!)
FLUSH PRIVILEGES;
4. my.cnf Härtung:
[mysqld]
# Nur auf localhost lauschen:
bind-address = 127.0.0.1
# Oder: spezifische IP: bind-address = 10.0.2.5
# SSL aktivieren:
ssl-ca=/etc/mysql/ssl/ca.pem
ssl-cert=/etc/mysql/ssl/server-cert.pem
ssl-key=/etc/mysql/ssl/server-key.pem
require_secure_transport=ON # Erzwingt SSL für alle Verbindungen!
# Audit-Logging (Enterprise oder MariaDB Audit Plugin):
plugin-load-add=server_audit
server_audit_logging=ON
server_audit_events=CONNECT,QUERY_DDL,QUERY_DML
# Binary Log für PITR (Point-in-Time-Recovery):
log_bin = /var/log/mysql/mysql-bin.log
expire_logs_days = 7
5. Passwort-Validierung:
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.number_count=1;
SET GLOBAL validate_password.special_char_count=1;
Microsoft SQL Server Härtung
MSSQL: Sichere Konfiguration
1. SA-Account deaktivieren:
-- SA-Account ist Legacy, sollte niemals genutzt werden!
ALTER LOGIN [sa] DISABLE;
ALTER LOGIN [sa] WITH NAME = [sa_disabled]; -- Umbenennen als weitere Barriere
-- Windows Authentication bevorzugen (Active Directory Integration!)
2. Least Privilege für Anwendungen:
-- Anwendungs-Login anlegen:
CREATE LOGIN [AppLogin] WITH PASSWORD = 'StarkesPasswort123!',
CHECK_POLICY = ON, -- Passwort-Policy erzwingen
CHECK_EXPIRATION = ON; -- Passwort-Ablauf
-- Database User mit minimalem Privilege:
USE [MyDatabase];
CREATE USER [AppUser] FOR LOGIN [AppLogin];
-- Rolle statt direkte Berechtigungen:
EXEC sp_addrolemember 'db_datareader', 'AppUser';
EXEC sp_addrolemember 'db_datawriter', 'AppUser';
-- NICHT: db_owner oder sysadmin!
3. Surface Area Configuration:
-- Nicht benötigte Features deaktivieren:
EXEC sp_configure 'xp_cmdshell', 0; -- KEIN Shell-Zugriff!
EXEC sp_configure 'remote access', 0;
EXEC sp_configure 'Ole Automation Procedures', 0;
EXEC sp_configure 'Ad Hoc Distributed Queries', 0;
RECONFIGURE;
4. SQL Server Audit:
-- Audit auf Server-Ebene:
CREATE SERVER AUDIT [SecurityAudit]
TO FILE (FILEPATH = N'C:\SQLAudit\')
WITH (QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE);
ALTER SERVER AUDIT [SecurityAudit] WITH (STATE = ON);
CREATE SERVER AUDIT SPECIFICATION [ServerAuditSpec]
FOR SERVER AUDIT [SecurityAudit]
ADD (SUCCESSFUL_LOGIN_GROUP),
ADD (FAILED_LOGIN_GROUP),
ADD (SERVER_ROLE_MEMBER_CHANGE_GROUP),
ADD (DATABASE_PERMISSION_CHANGE_GROUP)
WITH (STATE = ON);
5. Transparent Data Encryption (TDE):
-- Daten-at-Rest verschlüsseln:
USE master;
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'MasterKeyPasswort!';
CREATE CERTIFICATE TDECert WITH SUBJECT = 'TDE Certificate';
USE MyDatabase;
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE TDECert;
ALTER DATABASE MyDatabase SET ENCRYPTION ON;
-- → Alle Datenbankdateien (.mdf, .ndf, .ldf) verschlüsselt
-- Backup des Master Keys und Zertifikats KRITISCH!
Verschlüsselung und Backup-Sicherheit
Sensitive Daten in der Datenbank schützen:
Column-Level Encryption (für höchste Sensitivität):
PostgreSQL - pgcrypto:
CREATE EXTENSION pgcrypto;
-- Verschlüsseltes Speichern:
INSERT INTO kunden (name, email, iban)
VALUES (
'Max Mustermann',
pgp_sym_encrypt('max@example.de', 'EncryptionKey123!'),
pgp_sym_encrypt('DE89 3704 0044 0532 0130 00', 'EncryptionKey123!')
);
-- Entschlüsseln nur bei Bedarf:
SELECT name, pgp_sym_decrypt(iban::bytea, 'EncryptionKey123!') AS iban_plain
FROM kunden WHERE id = 1;
-- BESSER: Key aus KMS/Vault holen, nicht hardcoded!
Password Hashing (NIEMALS Klartext-Passwörter!):
-- Argon2id (beste Wahl für neue Systeme):
-- PHP: password_hash($password, PASSWORD_ARGON2ID)
-- Python: argon2-cffi library
-- Node: argon2 library
-- bcrypt (etabliert, weit verbreitet):
UPDATE users SET password_hash = crypt('passwort', gen_salt('bf', 12))
WHERE id = 1;
-- Verifizieren:
SELECT (password_hash = crypt('eingabe', password_hash)) AS valid FROM users WHERE id=1;
Backup-Sicherheit:
Backup-Verschlüsselung (PostgreSQL mit pg_dump):
# Verschlüsseltes Backup:
pg_dump mydb | openssl enc -aes-256-cbc -pbkdf2 -out backup.enc -pass env:BACKUP_KEY
# Entschlüsseln:
openssl enc -aes-256-cbc -d -pbkdf2 -in backup.enc -pass env:BACKUP_KEY | psql mydb
# AWS: RDS-Backups automatisch mit KMS verschlüsselt (wenn aktiviert!)
aws rds create-db-snapshot --db-instance-identifier mydb \
--db-snapshot-identifier mydb-backup-2026-03-04
# KMS Key ID im RDS-Parameter: storage-encrypted=true, kms-key-id=...
Backup-Zugriffskontrolle:
□ Backups in separatem Storage-Account/Bucket
□ Cross-Region-Replikation für DR
□ IAM: nur Backup-Service-Account hat Write-Zugang
□ Niemand hat Delete-Zugang ohne MFA (S3 Object Lock, Azure Immutable Blob)
□ Backup-Wiederherstellung testen! (mindestens monatlich)
SQL Injection Prevention
SQL Injection vollständig verhindern:
FALSCH - String-Konkatenation (NIEMALS!):
# Python (SCHLECHT):
query = "SELECT * FROM users WHERE username = '" + username + "'"
cursor.execute(query)
# Angreifer: username = "admin' OR '1'='1"
# Query: SELECT * FROM users WHERE username = 'admin' OR '1'='1'
# → Gibt ALLE User zurück!
RICHTIG - Prepared Statements:
# Python (SICHER):
query = "SELECT * FROM users WHERE username = %s"
cursor.execute(query, (username,))
# Parameter wird immer als Datenwert behandelt, nie als SQL!
# Java / JDBC:
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ?"
);
stmt.setString(1, username);
# Node.js / pg:
const result = await pool.query(
'SELECT * FROM users WHERE username = $1',
[username]
);
# PHP / PDO:
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username');
$stmt->execute(['username' => $username]);
ORM verwenden (verhindert SQL Injection by Default):
# Django ORM (Python):
User.objects.filter(username=username) # Automatisch parametrisiert
# Sequelize (Node.js):
await User.findOne({ where: { username: username } })
# Entity Framework (C#):
context.Users.Where(u => u.Username == username).FirstOrDefault()
ACHTUNG: Raw Queries in ORMs sind trotzdem gefährlich!
# Django RAW (gefährlich wenn nicht parametrisiert!):
User.objects.raw('SELECT * FROM users WHERE username = %s', [username]) # OK
User.objects.raw(f'SELECT * FROM users WHERE username = {username}') # FALSCH!
WAF (Web Application Firewall) als zusätzliche Schicht:
→ ModSecurity mit OWASP Core Rule Set (CRS)
→ AWS WAF mit SQL Injection Ruleset
→ Azure Application Gateway mit WAF
→ NICHT als einziger Schutz - Defense in Depth!
→ WAF umgeht man mit Obfuscation: /**/UNION/**/ SELECT...
→ Prepared Statements + WAF = beste Kombination
Stored Procedures (NICHT als SQL-Injection-Schutz!):
→ Stored Procedures können auch SQL Injection enthalten (wenn EXEC(@string))
→ Parametrisierte Stored Procedures: sicher
→ Dynamisches SQL in SP: gefährlich
Datenbanksicherheit ist ein kontinuierlicher Prozess, keine Einmalmaßnahme. Neue Entwickler fügen unsicheren Code hinzu, Konfigurationen ändern sich, neue Systeme werden angebunden. AWARE7 prüft Datenbankimplementierungen als Teil von Applikations-Penetrationstests - von SQL Injection bis zu Berechtigungsanalyse und Audit-Log-Review.
Applikations-Penetrationstest anfragen | Penetrationstest Web-Applikationen
Nächster Schritt
Unsere zertifizierten Sicherheitsexperten beraten Sie zu den Themen aus diesem Artikel — unverbindlich und kostenlos.
Kostenlos · 30 Minuten · Unverbindlich
