Worum es geht
Manche Werte sollen nicht lesbar in der Datenbank stehen, etwa eine IBAN oder eine Steuernummer. Wer die Datenbank oder eine Sicherung in die Hände bekommt, soll damit nichts anfangen können.
Dafür setzt du am Textfeld im Hub die Regel verschlüsselt (@encrypted). CDMS verschlüsselt den Wert dann vor dem Speichern mit AES-256-GCM und entschlüsselt ihn beim Lesen. Der Client merkt davon nichts: Er schickt Klartext und bekommt Klartext.
Der Weg eines Wertes
sequenceDiagram
participant C as Client
participant D as CDMS
participant DB as Datenbank
C->>D: POST iban = "DE44 5001 …"
D->>D: Regeln prüfen (am Klartext)
D->>D: verschlüsseln, neuer Zufalls-IV
D->>DB: speichert "enc:v1:fdd5117f:InOkKngP…"
D->>DB: liest das Objekt für die Antwort
D->>D: entschlüsseln
D-->>C: 200, iban = "DE44 5001 …"
Die gespeicherte Form beginnt immer mit enc:v1:, dann folgt die Kennung des Schlüssels, dann der Geheimtext. Jede Verschlüsselung nimmt einen neuen Zufallswert (IV). Zwei gleiche IBANs stehen deshalb verschieden in der Datenbank.
Das Verschlüsseln erledigt ein mitgelieferter Feld-Hook: EncryptedFieldHook aus dem Modul cdms-field-encryption. Du schreibst dafür keinen Code. Der Generator hängt den Hook an jedes Feld mit der Regel, und der Projektrahmen nimmt das Modul in die pom.xml auf. Hat das Feld noch eigene Feld-Hooks, sehen diese den Klartext: Verschlüsselt wird als letzter Schritt vor der Datenbank.
Den Schlüssel einstellen
Die Anwendung braucht einen Schlüssel aus 32 Zufallsbytes, in Base64 geschrieben:
openssl rand -base64 32
| Umgebungsvariable | Property | Bedeutung |
|---|---|---|
CODAMAI_CDMS_ENCRYPTION_KEY | codamai.cdms.encryption.key | der aktive Schlüssel, mit dem jeder Wert geschrieben wird |
CODAMAI_CDMS_ENCRYPTION_PREVIOUS_KEYS | codamai.cdms.encryption.previous-keys | frühere Schlüssel, kommagetrennt, nur zum Lesen |
Der Schlüssel gehört in ein Secret deiner Umgebung, nie ins Modell und nie ins Repository. Nur eine Anwendung, in der ein Feld verschlüsselt ist, braucht ihn. Dort startet sie ohne ihn nicht:
field-encryption-key-missing|codamai.cdms.encryption.key: a model encrypts a field (@encrypted), …
Ein Schlüssel, der nicht 32 Bytes lang ist, stoppt den Start ebenso (field-encryption-key-invalid).
Den Schlüssel wechseln
-
1Betrieberzeugt einen neuen Schlüssel
-
2Betriebsetzt ihn als
CODAMAI_CDMS_ENCRYPTION_KEYund schiebt den alten nachCODAMAI_CDMS_ENCRYPTION_PREVIOUS_KEYS -
3CDMSliest alte Werte mit dem alten Schlüssel, erkennbar an seiner Kennung im gespeicherten Wert
-
4CDMSverschlüsselt jeden Wert, der neu geschrieben wird, mit dem neuen Schlüssel
Einen alten Schlüssel entfernst du erst, wenn kein Wert mehr mit ihm gespeichert ist. Fehlt der Schlüssel eines gespeicherten Wertes, liefert CDMS ihn nicht aus, sondern antwortet mit 500 field-encryption-key-unknown|<Kennung>.
Werte, die noch im Klartext stehen
Stellst du ein Feld nachträglich auf verschlüsselt, stehen seine bisherigen Werte noch im Klartext in der Datenbank. CDMS erkennt sie am fehlenden enc:v1: und liefert sie unverändert aus. Beim nächsten Schreiben des Feldes wird der Wert verschlüsselt. Ein Schreibvorgang, der das Feld nicht sendet, etwa ein PATCH auf ein anderes Feld, lässt ihn, wie er ist.
Was mit einem verschlüsselten Feld nicht geht
| Vorhaben | Antwort |
|---|---|
| das Feld lesen, auch in einer Liste oder in der Historie | ja, entschlüsselt |
| das Feld schreiben (POST, PUT, PATCH) | ja, CDMS verschlüsselt |
| nach dem Feld filtern | 400 field-not-searchable|<Feld> |
| nach dem Feld sortieren | 400 field-not-searchable|<Feld> |
| das Feld zusätzlich „eindeutig“ machen | geht nicht: der Hub lehnt es ab, der Generator bricht ab |
| ein Zahlen- oder Datumsfeld verschlüsseln | geht nicht: die Regel gibt es nur an Textfeldern |
Filter und Sortierung arbeiten in der Datenbank, also mit der gespeicherten Form. Die sieht für jeden Wert anders aus. Ein Filter fände deshalb nie etwas, eine Sortierung ergäbe Zufall. Statt falsch zu antworten, lehnt CDMS beides ab. Aus demselben Grund kann die Datenbank keine Eindeutigkeit prüfen.
Fallen
Wie es weitergeht
- Wie ein Feld-Hook allgemein arbeitet: Feld-Hooks
- Werte vor bestimmten Personen verbergen: Geschützte Werte
- Welche Regeln es im Hub gibt: Im Hub modellieren