Konzepte, Schluesselverwaltung und Praxis
Volume-Verschluesselung schuetzt Daten nur gegen gestohlene Festplatten, nicht aber gegen einen kompromittierten Datenbank-Account, der ganz normal per SQL liest. Datenverschluesselung auf Spaltenebene schuetzt genau diese Luecke, verlangt aber durchdachte Entscheidungen bei Schluesselverwaltung, Suchbarkeit und Indizierung, die pauschale Volume-Verschluesselung nie stellen muss.
Inhaltsverzeichnis
- 1. Warum Verschluesselung auf Spaltenebene, nicht nur auf Datenbankebene
- 2. pgcrypto in PostgreSQL: symmetrische Verschluesselung praktisch
- 3. Deterministische vs. randomisierte Verschluesselung
- 4. Schluesselverwaltung: wo Schluessel niemals liegen duerfen
- 5. Anwendungsseitige vs. datenbank-native Verschluesselung
- 6. Verschluesselung und Indizierung: der Zielkonflikt
- 7. Format-Preserving Encryption fuer strukturierte Daten
- 8. Schluesselrotation ohne Downtime
- 9. Verschluesselungsansaetze im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum Verschluesselung auf Spaltenebene, nicht nur auf Datenbankebene
Datenverschluesselung auf Datenbankebene, oft als Transparent Data Encryption bezeichnet, verschluesselt die gesamte Datendatei auf der Festplatte. Diese Massnahme schuetzt zuverlaessig gegen physischen Diebstahl einer Festplatte oder eines Backups, das ohne den passenden Schluessel unlesbar bleibt. Sie schuetzt aber nicht gegen den weitaus haeufigeren Fall: einen kompromittierten Datenbank-Account, der ganz normal per SQL-Query liest, weil die Datenbank-Engine die Daten fuer eine laufende Verbindung transparent entschluesselt.
Datenverschluesselung auf Spaltenebene setzt genau hier an: Einzelne, besonders sensible Spalten werden zusaetzlich verschluesselt gespeichert, sodass selbst ein Account mit vollem SELECT-Zugriff auf die Tabelle nur Chiffretext sieht, wenn er nicht auch ueber den passenden Entschluesselungsschluessel verfuegt. Diese zusaetzliche Schutzschicht ist besonders relevant fuer Felder wie Sozialversicherungsnummern, Kreditkartendaten oder Gesundheitsdaten, bei denen regulatorische Vorgaben explizite Verschluesselung "at rest" auf Feldebene verlangen.
Der entscheidende Unterschied: Datenverschluesselung auf Spaltenebene trennt den Zugriff auf die Daten vom Zugriff auf den Schluessel. Ein Datenbank-Administrator mit vollem Zugriff auf alle Tabellen sieht bei korrekt implementierter Spalten-Verschluesselung trotzdem nur Chiffretext, wenn der Schluessel ausserhalb der Datenbank verwaltet wird. Diese Trennung ist ein zentrales Element von Defense-in-Depth, das reine Volume-Verschluesselung strukturell nicht bieten kann.
2. pgcrypto in PostgreSQL: symmetrische Verschluesselung praktisch
PostgreSQL bietet mit der Erweiterung pgcrypto native Funktionen fuer Datenverschluesselung auf Spaltenebene. Die Funktionen pgp_sym_encrypt() und pgp_sym_decrypt() implementieren symmetrische Verschluesselung nach dem OpenPGP-Standard direkt in SQL, ohne dass Anwendungscode kryptographische Bibliotheken selbst einbinden muss. Der Passphrase-Parameter fungiert als Schluessel, sollte aber niemals als Literal im SQL-Statement stehen, sondern aus einer sicheren externen Quelle stammen.
Ein wichtiger praktischer Punkt bei pgcrypto: Verschluesselte Spalten muessen als bytea statt als text oder varchar deklariert werden, weil das Ergebnis binaerer Chiffretext ist. Anwendungscode, der diese Spalten liest, muss die Entschluesselung explizit anfordern, was in der Praxis bedeutet, dass jede Query, die auf verschluesselte Felder zugreift, angepasst werden muss, statt transparent wie bei unverschluesselten Spalten zu funktionieren.
-- Enable the pgcrypto extension once per database
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Column-level data encryption: store as bytea, never as plain text
CREATE TABLE customers (
id SERIAL PRIMARY KEY,
first_name TEXT NOT NULL,
ssn_encrypted BYTEA NOT NULL -- encrypted column
);
-- Insert with encryption, passphrase from a secure external source
-- (never hardcode the passphrase in application code or SQL)
INSERT INTO customers (first_name, ssn_encrypted)
VALUES (
'Jane Doe',
pgp_sym_encrypt('123-45-6789', current_setting('app.encryption_key'))
);
-- Read with explicit decryption, requires the same key
SELECT
first_name,
pgp_sym_decrypt(ssn_encrypted, current_setting('app.encryption_key')) AS ssn
FROM customers
WHERE id = 1;
3. Deterministische vs. randomisierte Verschluesselung
Ein zentraler Designentscheid bei Datenverschluesselung auf Spaltenebene betrifft die Wahl zwischen deterministischer und randomisierter Verschluesselung. Randomisierte Verschluesselung erzeugt bei jeder Verschluesselung desselben Klartextwerts einen anderen Chiffretext, weil ein zufaelliger Initialisierungsvektor einfliesst. Das ist kryptographisch die sicherere Wahl, weil ein Angreifer selbst bei Zugriff auf viele Chiffretexte nicht erkennen kann, welche Zeilen denselben Klartext enthalten.
Der Nachteil randomisierter Datenverschluesselung: Man kann nicht direkt per WHERE ssn_encrypted = ... nach einem Wert suchen, weil derselbe Klartext bei jeder Verschluesselung einen anderen Chiffretext ergibt. Deterministische Verschluesselung loest dieses Problem, indem derselbe Klartext immer denselben Chiffretext erzeugt, was direkte Gleichheitssuche erlaubt, aber ein Sicherheitsrisiko einfuehrt: Ein Angreifer kann Muster erkennen, etwa dass zwei Kunden dieselbe Kreditkartennummer haben, ohne den Klartext selbst zu kennen.
-- Randomized encryption: different ciphertext each time, more secure
-- pgp_sym_encrypt includes a random session key by default
SELECT pgp_sym_encrypt('4111111111111111', 'key') != pgp_sym_encrypt('4111111111111111', 'key');
-- Returns TRUE: same plaintext, different ciphertext each call
-- Deterministic alternative: HMAC-based blind index for equality search
-- Store both the randomized ciphertext AND a deterministic search token
CREATE TABLE payments (
id SERIAL PRIMARY KEY,
card_number_encrypted BYTEA NOT NULL, -- randomized, for storage
card_number_search_hash TEXT NOT NULL -- deterministic HMAC, for lookup
);
INSERT INTO payments (card_number_encrypted, card_number_search_hash)
VALUES (
pgp_sym_encrypt('4111111111111111', current_setting('app.encryption_key')),
encode(hmac('4111111111111111', current_setting('app.hmac_key'), 'sha256'), 'hex')
);
-- Search uses the deterministic hash, never the randomized ciphertext
SELECT * FROM payments
WHERE card_number_search_hash = encode(hmac('4111111111111111', current_setting('app.hmac_key'), 'sha256'), 'hex');
4. Schluesselverwaltung: wo Schluessel niemals liegen duerfen
Die wirksamste Datenverschluesselung auf Spaltenebene wird wertlos, wenn der Schluessel neben den verschluesselten Daten liegt. Ein haeufiger, gefaehrlicher Fehler: Der Verschluesselungsschluessel wird in einer Konfigurationstabelle derselben Datenbank gespeichert, oder schlimmer, direkt im Anwendungscode hartcodiert. In beiden Faellen erhaelt jeder, der Zugriff auf die Datenbank oder das Repository bekommt, automatisch auch den Schluessel, und die gesamte Verschluesselung wird zur reinen Formalitaet.
Professionelle Datenverschluesselung nutzt ein dediziertes Key-Management-System wie AWS KMS, HashiCorp Vault oder Azure Key Vault, das Schluessel ausserhalb der Datenbank verwaltet, Zugriff granular protokolliert und Schluessel niemals im Klartext an Anwendungscode zurueckgibt, sondern nur Ver- und Entschluesselungsoperationen als Service anbietet. Die Anwendung ruft das KMS zur Laufzeit auf, erhaelt den entschluesselten Wert direkt zurueck, und der Rohschluessel verlaesst das KMS im Idealfall nie.
Ein zweistufiges Schluesselmodell mit einem Data Encryption Key pro Spalte oder Tabelle und einem uebergeordneten Key Encryption Key im KMS reduziert zusaetzlich das Risiko: Wird ein Data Encryption Key kompromittiert, ist nur die betroffene Spalte gefaehrdet, waehrend der Key Encryption Key im KMS geschuetzt bleibt und fuer die Rotation aller Data Encryption Keys genutzt werden kann.
5. Anwendungsseitige vs. datenbank-native Verschluesselung
Datenverschluesselung kann entweder in der Datenbank selbst per Funktion wie pgp_sym_encrypt stattfinden oder vollstaendig in der Anwendungsschicht, bevor Daten ueberhaupt an die Datenbank gesendet werden. Anwendungsseitige Verschluesselung bietet die staerkste Trennung: Die Datenbank sieht zu keinem Zeitpunkt Klartext, selbst ein vollstaendig kompromittierter Datenbankserver liefert einem Angreifer nur Chiffretext, weil Ver- und Entschluesselung ausschliesslich in der Anwendung passieren.
Der Nachteil anwendungsseitiger Datenverschluesselung: Datenbankfunktionen wie Aggregation, Sortierung oder Volltextsuche auf dem verschluesselten Feld sind unmoeglich, weil die Datenbank den Klartext nie sieht. Datenbank-native Verschluesselung mit pgcrypto erlaubt zumindest Entschluesselung innerhalb einer Query fuer nachgelagerte Verarbeitung, verlagert aber Vertrauen in die Datenbank-Engine selbst, die kurzzeitig Klartext im Arbeitsspeicher haelt.
-- Application-side encryption: database only ever sees ciphertext
-- Pseudocode showing the pattern, actual crypto happens in app code
function storeCustomer(customer) {
const encryptedSsn = encryptAES256(customer.ssn, getKeyFromKms());
db.query(
"INSERT INTO customers (first_name, ssn_encrypted) VALUES ($1, $2)",
[customer.firstName, encryptedSsn]
);
// Database process memory, logs and backups never contain plaintext
}
function readCustomerSsn(id) {
const row = db.query("SELECT ssn_encrypted FROM customers WHERE id = $1", [id]);
return decryptAES256(row.ssn_encrypted, getKeyFromKms());
// Decryption happens exclusively in application memory
}
6. Verschluesselung und Indizierung: der Zielkonflikt
Ein B-Tree-Index auf einer verschluesselten Spalte mit randomisierter Datenverschluesselung ist praktisch nutzlos, weil der Index nur auf Chiffretext sortiert, der keine Beziehung zur Klartext-Ordnung hat. Bereichssuchen wie WHERE betrag_encrypted BETWEEN ... AND ... funktionieren dadurch grundsaetzlich nicht auf verschluesselten Spalten, selbst mit einem vorhandenen Index.
Die praktikable Loesung fuer Gleichheitssuche ist der bereits gezeigte deterministische Blind-Index per HMAC, der einen separaten, indizierbaren Hash-Wert neben dem eigentlichen, randomisiert verschluesselten Wert speichert. Fuer Bereichssuchen auf verschluesselten numerischen Feldern existieren spezialisierte Verfahren wie Order-Preserving Encryption, die aber selbst gewisse Informationen ueber die relative Groessenordnung preisgeben und deshalb nur eingesetzt werden sollten, wenn Bereichssuche unverzichtbar ist und das Restrisiko akzeptiert wird.
7. Format-Preserving Encryption fuer strukturierte Daten
Format-Preserving Encryption ist eine spezielle Form der Datenverschluesselung, bei der der Chiffretext dieselbe Struktur und Laenge wie der Klartext behaelt. Eine 16-stellige Kreditkartennummer wird zu einer anderen 16-stelligen Zahl verschluesselt, statt zu binaerem Chiffretext beliebiger Laenge. Dieser Ansatz ist besonders wertvoll fuer bestehende Systeme, deren Datenbankschema und Validierungslogik feste Feldlaengen und -formate erwarten und nicht ohne aufwendige Migration geaendert werden koennen.
Der Nutzen von Format-Preserving Encryption bei Datenverschluesselung liegt darin, dass Legacy-Anwendungen, Reporting-Tools und Drittsysteme, die ein festes Format erwarten (etwa Luhn-valide Kreditkartennummern fuer Testzwecke), weiterhin funktionieren, ohne Schema-Aenderungen. Der Kompromiss: Format-Preserving Encryption bietet in der Praxis meist etwas schwaechere kryptographische Garantien als klassische randomisierte Verschluesselung, weil die erhaltene Struktur zwangslaeufig etwas Information ueber den Klartext preisgibt.
8. Schluesselrotation ohne Downtime
Schluesselrotation ist ein Pflichtbestandteil jeder ernsthaften Datenverschluesselung-Strategie, wird aber in der Praxis oft aufgeschoben, weil ein einfacher Ansatz sofortige Downtime bedeutet: alle Zeilen mit dem alten Schluessel entschluesseln und mit dem neuen Schluessel neu verschluesseln, waehrend die Anwendung stillsteht. Bei Millionen von Zeilen ist das in produktiven Systemen nicht akzeptabel.
Der produktionstaugliche Ansatz fuer Schluesselrotation bei Datenverschluesselung nutzt eine Versionsspalte, die angibt, mit welcher Schluesselversion eine Zeile verschluesselt wurde. Die Anwendung haelt beide Schluessel gleichzeitig vor, entschluesselt mit der in der Zeile vermerkten Version und verschluesselt neu geschriebene oder aktualisierte Zeilen immer mit dem aktuellen Schluessel. Ein Hintergrundprozess migriert schrittweise aeltere Zeilen auf den neuen Schluessel, ohne dass die Anwendung jemals stillsteht.
-- Key rotation pattern: version column tracks which key encrypted each row
ALTER TABLE customers ADD COLUMN key_version INT NOT NULL DEFAULT 1;
-- Application keeps both keys available during rotation
-- key_version = 1 uses the old key, key_version = 2 uses the new key
-- Background job migrates rows in small batches, no downtime
UPDATE customers
SET
ssn_encrypted = pgp_sym_encrypt(
pgp_sym_decrypt(ssn_encrypted, current_setting('app.encryption_key_v1')),
current_setting('app.encryption_key_v2')
),
key_version = 2
WHERE key_version = 1
AND id IN (SELECT id FROM customers WHERE key_version = 1 LIMIT 1000);
-- Repeat in batches until all rows use key_version = 2
-- Old key can be retired from the KMS only after the last row migrates
9. Verschluesselungsansaetze im Vergleich
Die folgende Tabelle vergleicht die wichtigsten Entscheidungspunkte bei Datenverschluesselung auf Spaltenebene und zeigt, welcher Ansatz fuer welchen Anwendungsfall passt.
| Anforderung | Nicht empfohlen | Empfohlener Ansatz | Grund |
|---|---|---|---|
| Schluesselspeicherung | Schluessel in derselben Datenbank | Dediziertes KMS ausserhalb der DB | Kompromittierung der DB entschluesselt nicht automatisch |
| Gleichheitssuche | WHERE auf randomisierten Chiffretext | Separater deterministischer HMAC-Hash | Suchbarkeit ohne Preisgabe der Verschluesselung |
| Maximale Sicherheit | Deterministische Verschluesselung ueberall | Randomisiert, deterministisch nur wo noetig | Musteranalyse fuer Angreifer erschwert |
| Legacy-Formatzwang | Schema-Migration erzwingen | Format-Preserving Encryption | Bestehende Validierung bleibt kompatibel |
| Schluesselrotation | Vollstaendige Downtime | Versionsspalte plus Batch-Migration | Rotation ohne Produktionsunterbrechung |
Kein einzelner Ansatz deckt alle Anforderungen ab. Datenverschluesselung auf Spaltenebene erfordert bewusste Kompromisse zwischen Suchbarkeit, Sicherheit und Kompatibilitaet mit bestehenden Systemen, die vor der Implementierung fuer jedes sensible Feld einzeln getroffen werden sollten.
Mironsoft
Datenverschluesselung, Schluesselverwaltung und Compliance-Umsetzung
Sensible Felder wirklich auf Spaltenebene schuetzen?
Wir konzipieren Datenverschluesselung auf Spaltenebene mit externem Schluesselmanagement, waehlen deterministische oder randomisierte Verfahren passend zum Anwendungsfall und richten Schluesselrotation ohne Downtime ein.
Verschluesselungs-Design
Pro Feld die passende Verschluesselungs- und Suchbarkeitsstrategie festlegen
KMS-Integration
Schluesselverwaltung ausserhalb der Datenbank produktionsreif anbinden
Rotation & Migration
Schluesselrotation ohne Downtime fuer bestehende Bestandsdaten umsetzen
10. Zusammenfassung
Datenverschluesselung auf Spaltenebene schliesst eine Luecke, die reine Volume-Verschluesselung offen laesst: den Schutz gegen einen kompromittierten Datenbank-Account mit normalem Lesezugriff. pgcrypto liefert in PostgreSQL die notwendigen Funktionen, aber der eigentliche Sicherheitsgewinn entsteht erst durch konsequente Trennung von Schluessel und Daten ueber ein dediziertes Key-Management-System.
Die Wahl zwischen deterministischer und randomisierter Datenverschluesselung entscheidet ueber Suchbarkeit versus Sicherheit, ein Blind-Index per HMAC kombiniert beides fuer Gleichheitssuche. Format-Preserving Encryption haelt Legacy-Systeme kompatibel, waehrend eine Versionsspalte Schluesselrotation ohne Produktionsausfall ermoeglicht. Jede Entscheidung sollte pro Feld einzeln getroffen werden, abhaengig davon, welche Abfragen auf dem verschluesselten Wert tatsaechlich noetig sind.
Datenverschluesselung auf Spaltenebene: Das Wichtigste auf einen Blick
pgcrypto
pgp_sym_encrypt und pgp_sym_decrypt fuer symmetrische Spalten-Verschluesselung, Spalte als bytea deklarieren.
Deterministisch vs. randomisiert
Randomisiert fuer maximale Sicherheit, deterministischer HMAC-Blind-Index nur wo Suchbarkeit zwingend noetig ist.
Schluessel ausserhalb der DB
Dediziertes KMS statt Schluessel in Konfigurationstabelle oder Anwendungscode.
Rotation ohne Downtime
Versionsspalte pro Zeile, Hintergrundprozess migriert schrittweise auf neuen Schluessel.