Diese Seite wurde maschinell übersetzt. Lesen Sie das englische Original. English

IBSurgeon-Bibliothek

So funktioniert die Firebird-Datenbankverschlüsselung

(c) Alexey Kovyazin, IBSurgeon, Alex Peshkoff, Firebird Project, 2021

Der Artikel basiert auf den Materialien des Workshops “Database Encryption” auf der Firebird Conference 2019 in Berlin, Deutschland. Er beschreibt, wie die Firebird-Datenbankverschlüsselung funktioniert, auf Server-Ebene, auf der Client-Seite, wie man die Datenbankverschlüsselung konfiguriert, wie man sie aus verschiedenen Arten von Anwendungen (Delphi, Java, .NET) verwendet. Die Beispiele des Artikels basieren auf dem IBSurgeon Firebird Encryption Framework (FEPF), können aber an die meisten der derzeit verfügbaren Implementierungen von Verschlüsselungs-Plugins angepasst werden.

Inhalt:

  1. Warum brauchen wir Datenbankverschlüsselung (und wann nicht)?
  2. Wie die Firebird-Datenbankverschlüsselung auf der Server-Seite funktioniert
  3. Welcher Teil der Datenbank wird verschlüsselt?
  4. Wann werden Datenseiten verschlüsselt?
  5. Wie schützt man die Schlüsselübertragung?
  6. Wie die Firebird-Verschlüsselung auf der Client-Seite funktioniert
  7. Native Anwendungen
  8. Java-Anwendungen
  9. .NET-Anwendungen
  10. Installation und Konfiguration
  11. Wie man den Verschlüsselungsfortschritt verfolgt
  12. Zusammenfassung

1. Warum brauchen wir Datenbankverschlüsselung (und wann nicht)?

Die Firebird-Datenbankverschlüsselung wurde in der Firebird 3.0-Version eingeführt (zusammen mit der Übertragungsprotokoll-Verschlüsselung, die oft mit dem behandelten Thema verwechselt wird) und hat die Möglichkeiten zum Schutz von Daten vor unbefugtem Zugriff erheblich erweitert. Sie ist jedoch kein Allheilmittel, und es ist notwendig, ihre Stärken und Schwächen zu verstehen, um sie richtig einzusetzen.

In diesem Artikel betrachten wir die internen Details der Datenbankverschlüsselung auf grundlegender Ebene, um Entwicklern von Firebird-Anwendungen ein besseres Verständnis dafür zu geben, wie die Datenbankverschlüsselung funktioniert.

Warum brauchen wir also Datenbankverschlüsselung?

  1. Zum Schutz von Datenbanken mit sensiblen/wertvollen Daten vor “physischem” Diebstahl. Wenn ein Eindringling die Festplatte mit einer Kopie der verschlüsselten Datenbank stiehlt oder auf irgendeine Weise eine Kopie einer Datenbankdatei erhält, ist es ohne den entsprechenden Schlüssel nicht möglich, Daten daraus zu lesen, und es ist auch nicht möglich, Wiederherstellungssoftware wie FirstAID zu verwenden, um die Daten zu extrahieren. Natürlich hängt es vom Verschlüsselungsalgorithmus und der Rechenleistung ab, aber das Knacken von AES256 wird zu lange dauern oder zu teure Rechenressourcen erfordern.
  2. Zum Schutz der Datenbank vor dem Zugriff durch nicht autorisierte Anwendungen ohne Verschlüsselungsschlüssel. Beispiele sind:
    • direkter Zugriff mit einem Entwicklerwerkzeug durch eine nicht autorisierte Person, um sensible Informationen zu ändern (z. B. Geldtransaktionen),
    • Ändern oder Stehlen von Geschäftslogik (Texte von gespeicherten Prozeduren und Triggern).
  3. Schutz von Datenbanken mit vorbefüllten Daten vor dem Export in oder dem Zugriff durch nicht autorisierte Anwendungen.
  4. Regierungen haben in letzter Zeit Datenschutzgesetze erlassen (GDPR/DSVGO in Europa, LGPD in Brasilien usw.), die unter anderem ein höheres Schutzniveau für personenbezogene und andere sensible Daten erfordern, und Verschlüsselung wird als eine der angemessenen Schutzmaßnahmen genannt.

Wann ist Datenbankverschlüsselung nicht nützlich?

In einigen Fällen ist es besser, die Sicherheits- und Konfigurationsfunktionen von Firebird zu verwenden, anstatt der Datenbankverschlüsselung:

  • Zum Schutz der Datenbank vor physischem Zugriff über das Netzwerk ist es notwendig, den Netzwerkzugriff zu konfigurieren: d. h. freigegebene Netzwerkordner zu schließen, da Firebird keinen freigegebenen Netzwerkzugriff auf Datenbankdateien benötigt, und die Sicherheitsberechtigungen zu verschärfen (für Linux zum Beispiel müssen Datenbankdateien Lese-/Schreibzugriff nur für den Benutzer “firebird” haben).
  • Um den Zugriff auf die spezifische Datenbank für eine bestimmte Teilmenge von Benutzern einzuschränken, ist die einfachere Lösung die Konfiguration einer separaten Sicherheitsdatenbank.
  • Um den Zugriff auf die Datenbankobjekte (Tabellen, gespeicherte Prozeduren) einzuschränken, ist es notwendig, die Firebird-Sicherheitsmechanismen zu verwenden: Benutzer, Rollen usw.

Natürlich sind beide obigen Listen unvollständig, aber sie geben Ihnen einen Eindruck davon, wann Sie Datenbankverschlüsselung benötigen oder nicht.

2. Wie die Firebird-Datenbankverschlüsselung auf der Server-Seite funktioniert

Lassen Sie uns die internen Details der Firebird-Datenbankverschlüsselung durchgehen und mit dem Serverteil beginnen.

2.1. Welcher Teil der Datenbank wird verschlüsselt?

Das erste, was wir betrachten müssen, ist: Welcher Teil der Datenbank wird verschlüsselt? Wie Sie wahrscheinlich wissen, besteht eine Firebird-Datenbank aus Teilen gleicher Größe, die “Datenbankseiten” genannt werden. Es gibt mehrere Arten solcher Seiten, und jede Art dient einem bestimmten Zweck.

Unten sehen Sie die Abbildung mit den wichtigsten Datentypen:

Abbildung 1. Arten von Datenbankseiten

Einige Seiten sind dafür ausgelegt, Benutzerdaten zu speichern, und andere werden benötigt, um Systeminformationen zu speichern, wie Transaktionen und Seiteninventarseiten (weitere Details zu Datenbankseiten sind hier verfügbar).

Wenn eine Firebird-Datenbank verschlüsselt wird, werden nur Seiten mit Benutzerdaten verschlüsselt: Datenseiten, Indizes, Generatoren und BLOBs:

Abbildung 2. Nur Datenbankseiten mit Benutzerdaten werden verschlüsselt

Bitte beachten Sie, dass sich Datenbank-Metadaten (gespeicherte Prozeduren, Tabellen, Views, Trigger, Generatornamen usw.) innerhalb des Teils der Engine, der für die Verschlüsselung verantwortlich ist, nicht von “Benutzerdaten” unterscheiden und verschlüsselt werden.

Warum werden Systemseiten nicht verschlüsselt? Hauptsächlich aus Leistungsgründen und aufgrund der Tatsache, dass sie keine sensiblen Daten enthalten, die Schutz erfordern.

Die Datenbank-Header-Seite wird nicht verschlüsselt, weil sie Informationen enthält, die für die Verschlüsselung benötigt werden (z. B. den Schlüsselnamen).

2.2. Wann werden Datenseiten verschlüsselt?

Wenn ein Benutzer ein SELECT aus der verschlüsselten Datenbank ausführt, werden die Daten aus der verschlüsselten Datei gelesen, kommen aber im Anwendungsraster mit dem Resultsatz in unverschlüsselter Form an.

Betrachten wir die Details dieses Prozesses:

Abbildung 3. Wann werden Datenbankseiten verschlüsselt?

Normalerweise beginnt der Prozess mit einer Reihe von Lesevorgängen von Datenbankseiten aus einer Datenbankdatei, und diese werden im Dateicache des Betriebssystems zwischengespeichert.

Firebird kann auch so konfiguriert werden, dass der Dateicache umgangen und nur der eigene Cache verwendet wird, aber standardmäßig wird der Dateicache verwendet.

Danach liest Firebird Seiten und legt sie in den Firebird-Seitencache (dieser wird durch den Parameter DefaultDBCachePages in firebird.conf und/oder databases.conf oder auf der Datenbank-Header-Seite definiert).

Dann werden Seiten aus dem Cache für das Resultset der jeweiligen SQL-Anweisung (SELECT in unserem Beispiel) ausgewählt.

Die folgende Abbildung zeigt Details:

Abbildung 4. Seiten werden zwischen dem Firebird-Cache und dem OS-Dateicache verschlüsselt

Datenbankseiten werden also im OS-Dateicache verschlüsselt, kommen aber unverschlüsselt im Firebird-Seitencache an und umgekehrt.

Der Teil der Firebird-Software, der für die Verschlüsselung/Entschlüsselung verantwortlich ist, wird “Verschlüsselungs-Plugin” genannt. Da die meisten Plugin-Implementierungen (den Autoren bekannt) DbCrypt genannt werden, bezeichnen wir es als DbCrypt.

In der folgenden Abbildung sehen Sie Varianten für Windows (DbCrypt.dll) und Linux (libDbCrypt.so):

Abbildung 5. Das Verschlüsselungs-Plugin (DbCrypt) führt die Verschlüsselung/Entschlüsselung durch

Wenn Sie dieses Bild lange genug ansehen, wird die nächste Frage ziemlich schnell auftauchen: Wie erhält DbCrypt den richtigen Schlüssel zum Verschlüsseln/Entschlüsseln von Datenbankseiten?

Die Antwort - es gibt ein weiteres Plugin für die Schlüsselverwaltung.

Der typische Name für die Schlüsselverwaltung ist KeyHolder, der als Schlüsselspeicher-/Verwaltungseinrichtung für das Verschlüsselungs-Plugin (DbCrypt) dient. KeyHolder implementiert die Schnittstelle für die Schlüsselverwaltung, die von DbCrypt verwendet wird.

Abbildung 6. DbCrypt und KeyHolder

Was bedeutet “Schlüsselverwaltung”?

Im einfachsten Fall kann DbCrypt Schlüssel aus der Datei auf dem Server lesen. Die Datei kann eine einfache Klartextdatei sein, die an einem “geheimen” Ort oder auf einem USB-Stick versteckt werden kann, oder eine verschlüsselte Datei (z. B. mit der Windows Crypto API oder mit einem eingebauten internen Schlüssel).

Die Schlüsseldatei kann mehrere Schlüssel enthalten, die aus Bequemlichkeit als benannte Liste gespeichert sind, und kann wie folgt aussehen (das folgende Beispiel stammt aus dem IBSurgeon-Encryption Framework):

Code
Key=Red 0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,
Key=Green 0xab,0xd7,0x34,0x63,0xae,0x19,0x52,0x00,0xb8,0x84,0xa3,0x44,0xbd,0x11,0x9f,0x72,0xe0,0x04,0x68,0x4f,0xc4,0x89,0x3b,0x20,0x8d,0x2a,0xa7,0x07,0x32,0x3b,0x5e,0x74,

Wenn die Datenbank verschlüsselt ist, bleiben ihre Header-Seiten unverschlüsselt, um Informationen über das Verschlüsselungs-Plugin und den Namen des Schlüssels zu speichern, und Sie können diese Informationen mit dem Befehl “gstat -h datenbankname” sehen:

Code
Database header page information:
....
Creation date    Jan 11, 2017 15:12:20
Attributes       force write, encrypted, plugin DBCRYPT

Variable header data:
 Crypt checksum: MUB2NTJqchh9RshmP6xFAiIc2iI=
 Key hash:       ask88tfWbinvC6b1JvS9Mfuh47c=
 Encryption key name:    RED
 Sweep interval:         0
*END*

DbCrypt kann Seiten für mehrere Datenbanken und mehrere Schlüssel verarbeiten:

Abbildung 7. Mehrere Schlüssel für mehrere Datenbanken auf demselben Server (d. h. Firebird-Instanz)

Auswahl des richtigen Schlüssels

Entwickler stellen oft die Frage: “Wie erkennt das Plugin, welcher Schlüssel für welche Datenbank ist?” Die Antwort ist ziemlich einfach: über den Schlüsselnamen, der auf der Header-Seite der Datenbank gespeichert ist.

Seltener, aber dennoch wichtige Frage - was ist, wenn der Schlüsselname wie im Header aufgezeichnet ist, aber der Schlüsselwert unterschiedlich ist? Um Seitenlesefehler aufgrund des falschen Schlüssels zu verhindern, speichert das DbCrypt-Plugin eine verschlüsselte Testsequenz (Ziffern 0…F) im Header, und wenn der Schlüssel aktiviert wird, versucht das Plugin, die Beispieldaten mit einem Schlüssel zu verschlüsseln und seinen Hash mit dem gespeicherten Ergebnis zu vergleichen, um sicherzustellen, dass der übergebene Schlüsselwert tatsächlich für diese bestimmte Datenbank korrekt ist.

Der Ansatz, bei dem das Verschlüsselungs-Plugin Schlüssel direkt liest, ist einfach und vorteilhaft für Debugging, Leistungstests usw., da er die Verschlüsselung transparent implementiert: d. h. Client-Anwendungen und Entwicklerwerkzeuge wissen nicht, dass die Datenbank verschlüsselt ist.

In der Realität müssen wir jedoch den Zugriff von Anwendungen auf die Datenbank einschränken: Nur Client-Anwendungen, die einen Schlüssel haben, sollten sich mit der verschlüsselten Datenbank verbinden können.

Dafür benötigen wir das KeyHolder-Plugin, um den Schlüssel von der Client-Anwendung (die sich normalerweise auf einem anderen Computer befindet) über das Firebird-Netzwerkprotokoll zu erhalten.

2.3. Wie schützt man die Schlüsselübertragung?

Es ist möglich, dass wir die Datenbank in der Situation schützen wollen, in der der Kunde beschließt, direkten Zugriff auf die verschlüsselte Datenbank zu erhalten, unter Umgehung der autorisierten Anwendungen (viele Anbieter möchten Daten vor direktem Zugriff schützen, entweder schreibgeschützt oder lesend-schreibend).

Dies entspricht der Situation, in der ein Eindringling Zugriff auf den Server hat, aber keine Schlüssel besitzt.

Betrachten wir die folgenden Angriffsszenarien, um Schlüssel auf der Serverseite abzufangen:

  1. Wenn der Eindringling das gefälschte Verschlüsselungs-Plugin (DBCrypt.dll) erstellt und auf dem Server platziert, und wenn KeyHolder den Schlüssel übergibt, erstellt das gefälschte DbCrypt einen Dump des Schlüssels:

Abbildung 8. Angriff mit gefälschter DbCrypt.dll

  1. Wenn der Eindringling eine gefälschte firebird.exe-Datei erstellt und damit einen Dump erstellt:

Abbildung 9. Angriff mit gefälschter firebird.exe

Um sich vor solchen Angriffen zu schützen, müssen gute Implementierungen von Verschlüsselungs- und Schlüsselverwaltungs-Plugins den Schlüsselaustausch schützen.

Der Schlüsselaustausch kann mit asymmetrischer Verschlüsselung mit einem Paar aus öffentlichem/privatem Schlüssel geschützt werden.

Diese Schlüssel werden während des Build-Prozesses generiert und für das spezifische Paar von Verschlüsselungs- und Schlüsselverwaltungs-Plugins eingebaut. Für den besten Schutz ist es notwendig, speziell gebaute Paare von DbCrypt/KeyHolder zu verwenden.

Wenn DbCrypt und KeyHolder die Schlüssel austauschen, verwenden sie das folgende Protokoll (es ist vereinfacht, aber die Idee ist klar, denke ich):

Code
DbCrypt → KeyHolder:
	Gib mir den Datenbankschlüssel mit diesem Salt
KeyHolder:
	Verschlüsselt DbKey mit öffentlichem Schlüssel unter Verwendung des Salts von DbCrypt
	Überträgt den verschlüsselten DbKey an DbCrypt
DbCrypt:
	Entschlüsselt DbKey mit privatem Schlüssel
	Validiert die Korrektheit des Salts
	Bereit zur Arbeit

Mehr oder weniger dasselbe Protokoll wird verwendet, um Schlüssel zwischen Instanzen von KeyHolder auszutauschen, sowie für den Schlüsselaustausch zwischen einer Client-Anwendung und KeyHolder.

Bitte beachten Sie, dass die Verschlüsselung und Korrektheit der übertragenen Schlüssel von der Plugin-Implementierung abhängen; die Firebird-Engine bietet nur einen grundlegenden Low-Level-Übertragungsdienst „sende N Bytes von dieser Plugin-Instanz an jene Plugin-Instanz“.

Zusammenfassung für den serverseitigen Teil der Verschlüsselung

  • Ver-/Entschlüsselung erfolgt durch das Datenbank-Verschlüsselungs-Plugin (DbCrypt), Seite für Seite, während des Datenaustauschs zwischen dem Betriebssystem-Dateicache und dem Firebird-Seitencache
  • Die Schlüsselverwaltung kann auf einfache Weise implementiert werden, wenn DbCrypt Schlüssel direkt liest, aber normalerweise erfolgt dies mit einem Schlüsselverwaltungs-Plugin (KeyHolder)

Jetzt wollen wir entdecken, wie Client-Anwendungen mit verschlüsselten Datenbanken arbeiten.

3. Wie Firebird-Verschlüsselung auf der Client-Seite funktioniert

3.1. Native Anwendungen

Um zu verstehen, was passiert, wenn eine Client-Anwendung eine Verbindung zur verschlüsselten Datenbank herstellt, betrachten wir den regulären Verbindungsprozess zur nicht verschlüsselten Datenbank für native Anwendungen.

Bitte beachten Sie: Ab hier und im Folgenden bedeutet „nativ“, dass eine solche Anwendung eine Netzwerkverbindung mit dem Server über fbclient.dll herstellt; normalerweise ist eine solche App in Delphi, C++, PHP gebaut. Im Gegensatz zu nativen Anwendungen implementieren Java und .NET ihre eigene Version des Protokolls; diese werden weiter unten betrachtet.

Verbindungsprozess:

  1. Die Client-Anwendung lädt die Client-Bibliothek
  2. fbclient.dll - native Windows-Apps
  3. libfbclient.so - native Linux-Apps
  4. Die Client-Anwendung initiiert eine Verbindung und sendet
  5. Benutzername, z. B. SYSDBA
  6. Passwort, z. B. masterkey
  7. Pfad/Alias der Datenbank

Im Fall einer verschlüsselten Datenbank ist ein zusätzlicher Schritt erforderlich: Es ist notwendig, den Namen des Verschlüsselungsschlüssels und seinen Wert zu übergeben.

Es ist wichtig zu sagen, dass die Schlüsselübergabe vor der regulären Verbindung erfolgen sollte, da Daten-Seiten mit Metadaten, einschließlich Datenbankbesitzername, Zeichensatz usw., verschlüsselt sind.

Das führt uns also zu Folgendem:

  1. Ein zusätzlicher Netzwerk-Roundtrip ist notwendig, um den Schlüssel vor der regulären Verbindung zu übergeben
  2. Die Schlüsselübertragung von der Client-Anwendung an Firebird erfordert Codierung mit Verwendung asymmetrischer Verschlüsselung und Implementierung einer Callback-Schnittstelle; das kann ziemlich komplex sein. Um diese Aufgabe zu vereinfachen, stellen Plugin-Anbieter ein Beispiel für den Verbindungscode bereit, oder, wie im IBSurgeon-Plugin-Framework, erstellen sie die zusätzliche Bibliothek fbcrypt.dll/libfbcrypt.so, die eine einfach zu verwendende, geeignete Schnittstelle zur Übertragung von Schlüsseln von der Client-Anwendung implementiert.

Um eine native Anwendung (die fbclient.dll verwendet) mit der verschlüsselten Datenbank zu verbinden, müssen 3 Aufrufe durchgeführt werden. Unten ist ein Delphi-Beispiel (vereinfacht, ohne Fehlerbehandlung):

Im BeforeConnect-Ereignishandler:

Code
fbcrypt_init(PAnsiChar(‘C:\Firebird30.bclient.dll’));
fbcrypt_key(‘RED’, ‘0xec,0xa1,0x52,0xf6,...’));
fbcrypt_callback(nil);

 // Dann wie gewohnt verbinden
Database1.Active:=True;

In der Abbildung unten sehen Sie die Übersicht des Verbindungsprozesses mit einer verschlüsselten Datenbank in der nativen Anwendung:

Abbildung 10. Verbindungsprozess zur verschlüsselten Datenbank für native Anwendungen

Was ist mit Thread-Sicherheit im Fall von Multi-Thread-Client-Anwendungen?

Lassen Sie mich einige allgemeine Punkte zur Implementierung von Multi-Thread-Client-Anwendungen in Erinnerung rufen.

Seit Firebird 2.5 können mehrere Threads innerhalb der Anwendung sicher die einzelne Verbindung (Attachment) zur Datenbank verwenden, da die gesamte notwendige Synchronisierung innerhalb der fbclient.dll erfolgt.

In diesem Fall können die Threads jedoch nur nacheinander mit der Verbindung arbeiten.

Das ist in Ordnung für Anwendungen, die keinen Hochleistungs-Datenaustausch mit der Datenbank erfordern - wenn es kein Problem ist, auf die Ausführung einer SQL-Abfrage aus einem Thread zu warten, während ein anderer Thread eine andere SQL ausführt, ist es einfacher, ein einfaches Modell zu verwenden, bei dem 1 Verbindung zwischen mehreren Threads geteilt wird.

Wenn die Anwendung erfordert, SQL-Abfragen parallel auszuführen (d. h. es ist eine vollwertige Client-Anwendung), ist es besser, einen separaten Thread pro Verbindung zu verwenden.

Die Situation mit dem Schlüsselaustausch für die Verbindungen zu verschlüsselten Datenbanken ist etwas komplexer.

Bei jeder Verbindung überträgt die Client-Bibliothek die Schlüssel vom Client, aber das steht nicht direkt in Zusammenhang mit den Threads in der Client-Anwendung; die Situation hängt von der verwendeten API ab.

Wie Sie wissen, bietet die Firebird-Client-Bibliothek seit 3.0 zwei Arten von APIs: die neue objektorientierte API, basierend auf dem Konzept von Providern, und die Legacy-isc_-API, die als Workaround implementiert wurde, um die Kompatibilität mit alten Firebird-Treibern zu erhalten.

Wenn die neue objektorientierte Client-API verwendet wird, reicht es aus, einen Provider zu erstellen, ihn mit den notwendigen Schlüsseln zu versorgen und ihn dann für die neuen Verbindungen zu verwenden.

Wenn die isc_-Client-API verwendet wird, erstellt die Client-Bibliothek für jede Verbindung ihren eigenen temporären Provider, der für den Endbenutzer nicht direkt sichtbar oder zugänglich ist.

In diesem Fall wird der Schlüssel genau aus dem Thread übertragen, in dem isc_attach_database aufgerufen wird, und Thread-lokaler Speicher wird verwendet, um diesen Schlüssel zu speichern.

In der Praxis, da fast alle Client-Bibliotheken die isc_-API verwenden (derzeit verwendet unter den beliebten Treibern nur der Python-Treiber die OO-API), ist es notwendig, fb_database_crypt_callback() in jedem Thread aufzurufen, der sich mit der verschlüsselten Datenbank verbindet.

Schlüsselübertragungsaufrufe (fbcrypt.dll-Aufrufe im FEPF-Beispiel) müssen vor der Verbindung im selben Thread erfolgen, in dem die Verbindung hergestellt wird.

Wenn wir mit vielen Datenbanken arbeiten (z. B. SaaS-Webserver mit vielen Client-Datenbanken), ist es wichtig zu bedenken, dass jeder Aufruf von fbcrypt_key() einen Schlüssel zum KeyHolder-Speicher hinzufügt, der mit der aktuellen Verbindung verknüpft ist.

Schlüsselwerte müssen vor der Verbindung festgelegt werden; nach dem Verbindungsaufbau kann der Schlüsselwert nicht mehr geändert werden.

Im Fall des Trennens werden Schlüssel nicht entladen; sie bleiben im Speicher, bis fbcrypt.dll entladen wird.

3.2. Java-Anwendungen

Der Java-Treiber (JayBird) hat seine eigene Implementierung (in reinem Java) des Firebird-Verbindungsprotokolls. Jaybird 4 (und 3.0.4+) fügt Unterstützung für Firebird-3-Datenbankverschlüsselungs-Callbacks in der reinen Java-Implementierung des Version-13-Protokolls hinzu.

Aus dem Jaybird 4 Readme:

Die aktuelle Implementierung ist einfach und unterstützt nur das Antworten mit einem statischen Wert aus einer Verbindungseigenschaft. Beachten Sie, dass eine statische Wertantwort für Datenbankverschlüsselung nicht sehr sicher ist, da sie leicht zu Replay-Angriffen oder unbeabsichtigter Schlüsseloffenlegung führen kann.

Zukünftige Versionen von Jaybird (voraussichtlich 5) werden Plugin-Unterstützung für Datenbankverschlüsselungs-Plugins einführen, die einen komplexeren Callback erfordern.

Praktisch bedeutet das, dass wir den Wert für den Verschlüsselungs-Callback (normalerweise ein Schlüsselname und Schlüssel-Wert-Paar) in der Verbindungseigenschaft dbCryptConfig festlegen müssen.

Zum Beispiel:

Code
 edConnectionString.setText("jdbc:firebirdsql://localhost/g:/Databases/ODS12/crypt.fdb?lc_ctype=utf8&dbCryptConfig=MyKey:0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,");

Es ist auch möglich, einen String in base64 anzugeben - aus dem Readme:

Strings mit dem Präfix base64:: der Rest des Strings wird als base64 in Bytes dekodiert.

Die =-Padding-Zeichen sind optional, aber wenn sie vorhanden sind, müssen sie gültig sein (d. h. wenn Sie Padding verwenden, müssen Sie die richtige Anzahl von Padding-Zeichen für die Länge verwenden).

Wenn der base64-kodierte Wert + enthält, muss er in der JDBC-URL als %2B maskiert werden. Aus Gründen der Abwärtskompatibilität mit Jaybird 3 können wir nicht auf die URL-sichere Variante von base64 umschalten.

In der IBSurgeon-Implementierung des Schlüsselverwaltungs-Plugins wird eine solche Schlüsselübertragung als mehr oder weniger unsicher betrachtet: Wenn die Netzwerkprotokoll-Verschlüsselung nicht aktiviert ist ( übrigens, um sie zu aktivieren, setzen Sie in firebird.conf WireCrypt=Required und verwenden Sie keine Legacy-Authentifizierung), kann der Schlüssel leicht mit einem Netzwerkverkehrsanalysator wie WireShark erkannt werden. Um die Übertragung von Schlüsseln auf diese Weise zu ermöglichen, ist es daher notwendig, UnsafeClient=true in KeyHolder.conf des IBSurgeon-Schlüsselverwaltungs-Plugins zu setzen.

3.3 .NET-Anwendungen

Der Firebird.NET-Provider implementiert ein ähnliches Schema für den Schlüsselaustausch für verschlüsselte Datenbanken und erfordert ebenfalls, den Parameter UnsafeClient=true in KeyHolder.conf in FEPF zu setzen.

.NET-Beispiel der Verbindungszeichenfolge für verschlüsselte Datenbanken:

Code
string connectionString =
                "User=SYSDBA;" +
                "Password=masterkey;" +
                "Database=G:\\Databases\\ODS12.RYPT.FDB;" +
                "DataSource=localhost;" +
                "Port=3053;" +
                "Dialect=3;" +
                "Charset=NONE;" +
                "Role=;" +
                "Connection lifetime=15;" +
                "Pooling=true;" +
                "MinPoolSize=0;" +
                "MaxPoolSize=50;" +
                "Packet Size=8192;" +
                "ServerType=0;" +
                 "cryptkey = TXlLZXk6MHhlYywweG…...;";

Sie können feststellen, dass der Verschlüsselungsschlüssel anders aussieht als im Beispiel für native Anwendungen und JayBird; das liegt daran, dass es das Ergebnis einer Base64-Transformation ist. Um den Schlüssel für .NET- oder Java-Anwendungen zu erhalten, ist es notwendig, base64 aus dem String zu berechnen:

“MyKey:0xec,0xa1,0x52,0xf6,0x4d,0x27,0xda,0x93,0x53,0xe5,0x48,0x86,0xb9,0x7d,0xe2,0x8f,0x3b,0xfa,0xb7,0x91,0x22,0x5b,0x59,0x15,0x82,0x35,0xf5,0x30,0x1f,0x04,0xdc,0x75,”

und es als Parameter für “cryptkey=xxx;” mit “;” am Ende der Verbindungszeichenfolge zu verwenden.

4. Installation und Konfiguration

Um die Verwendung des Datenbank-Verschlüsselungs- und Schlüsselverwaltungs-Plugins zu ermöglichen, ist es notwendig, den Namen des Verschlüsselungs-Plugins in der Firebird-Konfigurationsdatei firebird.conf anzugeben:

Code
 KeyHolderPlugin = KeyHolder

Oder alternativ in databases.conf für den Alias der verschlüsselten Datenbank:

Code
myencrypted = C:\Temp\EMPLOYEE30.MPLOYEE30.FDB { KeyHolderPlugin = KeyHolder }

Dann ist es notwendig zu überprüfen, dass alle für das Plugin benötigten Dateien auf dem Server vorhanden sind.

Das folgende Beispiel ist für IBSurgeons FEPF, aber andere Plugins sind mehr oder weniger ähnlich:

In %FirebirdFolder$\plugins

Code
    • DbCrypt.dll
    • DbCrypt.conf
    • KeyHolder.dll
    • KeyHolder.conf - nur für den Debug-Modus!

In %FirebirdFolder$

Code
    • fbcrypt.dll
    • libcrypto-1_1-x64.dll
    • libssl-1_1-x64.dll
    • firebird.msg

Danach können wir die Testverschlüsselung auf dem Server durchführen, dazu in isql:

Code
isql.exe localhost:C:\Temp\EMPLOYEE30.MPLOYEE30.FDB -user SYSDBA -pass masterkey
SQL>alter database encrypt with dbcrypt key red;
SQL> show database;
Database: localhost:C:\Temp\EMPLOYEE30.MPLOYEE30.FDB
….
ODS = 12.0
Database encrypted
Default Character set: NONE

Wenn Sie unter Linux arbeiten, denken Sie daran, dass die Groß-/Kleinschreibung wichtig ist, daher lautet der Befehl:

Code
alter database encrypt with "DbCrypt" key Red;

Jetzt können wir den Client-Zugriff auf die verschlüsselte Datenbank testen. Dazu entfernen (oder umbenennen oder bearbeiten) wir die Konfigurationsdatei KeyHolder.conf und versuchen, mit der einfachen Testanwendung eine Verbindung zur verschlüsselten Datenbank herzustellen.

Dazu müssen wir im Ordner mit der Client-App die folgenden Dateien ablegen:

  • Demo-App von FEPF - CryptTest.exe (32bit)
  • Pflichtdateien:
    • fbclient.dll
    • fbcrypt.dll
    • libcrypto-1.1.dll
    • libssl-1.1-x64.dll
  • Optionale Dateien:
    • firebird.conf
    • in plugins
    • ◦ KeyHolder.conf
    • ◦ keyhodler.dll

Bei einigen Implementierungen von Schlüsselverwaltungs-Plugins ist es möglich, Schlüssel in der Client-Bibliothek zu laden (fbclient.dll), ohne die Client-Software zu modifizieren.

Dies ermöglicht die transparente Arbeit von Firebird-Entwicklertools (wie Firebird SQL Studio, DatabaseWorkbench, IBExpert, FlameRobin, RedExpert usw.) sowie die transparente Nutzung von Firebird-Befehlszeilentools (gfix.exe, nbackup.exe usw.).

5. So verfolgen Sie den Fortschritt der Verschlüsselung

Firebird verschlüsselt eine Datenbank nur, wenn aktive Verbindungen bestehen. Der Verschlüsselungsprozess läuft in einem separaten parallelen Thread, und bei großen Datenbanken kann die vollständige Verschlüsselung erhebliche Zeit in Anspruch nehmen.

Um den Verschlüsselungsprozess zu verfolgen, führen Sie entweder eine SQL-Abfrage aus MON$ aus:

Code
select mon$crypt_page * 100.0 / mon$pages as Percent from mon$database;
commit;

oder führen Sie das gstat-Tool mit dem speziellen Schalter aus:

Code
gstat -e dbname

Database "D:\ENCDB\TESTENCRYPT.FDB"
Gstat execution time Tue Mar 16 11:45:11 2021

Database header page information:
        Flags                   0
        Generation              10697
        System Change Number    3
        Page size               8192
        ODS version             12.0
        Oldest transaction      7053
        Oldest active           7054
        Oldest snapshot         7054
        Next transaction        7054
        Sequence number         0
        Next attachment ID      17834
        Implementation          HW=Intel/i386 little-endian OS=Windows CC=MSVC
        Shadow count            0
        Page buffers            0
        Next header page        0
        Database dialect        3
        Creation date           Oct 9, 2019 6:42:31
        Attributes              encrypted, plugin DBCRYPT

    Variable header data:
        Database backup GUID:   {866B4967-ED58-427E-A481-DB9206CEA2ED}
        Crypt checksum: MUB2NTJqchh9RshmP6xFAiIc2iI=
        Key hash:       ask88tfWbinvC6b1JvS9Mfuh47c=
        Encryption key name:    RED
        Database GUID:  {323FE494-1771-4608-E99D-C1B69C84578B}
        *END*

Data pages: total 105, encrypted 105, non-crypted 0
Index pages: total 95, encrypted 95, non-crypted 0
Blob pages: total 0, encrypted 0, non-crypted 0
Generator pages: total 1, encrypted 1, non-crypted 0
Gstat completion time Tue Mar 16 11:45:11 2021

Bitte beachten Sie, dass die Ausführung von gstat ein langwieriger Prozess sein kann.

6. Zusammenfassung

  1. Die Firebird-Datenbankverschlüsselung ist eine leistungsstarke Funktion, um die Informationen in den Datenbanken vor unbefugtem Zugriff zu schützen.
  2. Der Verschlüsselungsprozess erfordert eine serverseitige dynamische Bibliothek - das Verschlüsselungs-Plugin (normalerweise DbCrypt genannt) - und in den allermeisten Fällen das Schlüsselverwaltungs-Plugin (normalerweise KeyHolder genannt).
  3. Die sichere und zuverlässige Implementierung der DbCrypt- und KeyHolder-Plugins sollte unter Berücksichtigung der gängigsten Angriffsarten erfolgen.
  4. Um mit der verschlüsselten Datenbank zu arbeiten, müssen Client-Anwendungen den Verschlüsselungsschlüssel übertragen.
  5. Installation und Konfiguration des Verschlüsselungs-Plugins auf der Serverseite sind trivial; es erfordert 1 Parameter in der firebird.conf/databases.conf und mehrere Dateien.
  6. Der Verschlüsselungsprozess kann langwierig sein; er läuft in einem separaten Hintergrund-Thread, der Fortschritt kann über MON$-Aufrufe oder gstat verfolgt werden.

Was kommt als Nächstes?

Wir arbeiten an einem detaillierten Leistungstest der Firebird-Datenbankverschlüsselung. Im Allgemeinen ist die Leistung 4-8% geringer, aber das hängt von der Hardware und den Firebird-Einstellungen ab. Bleiben Sie dran!

Kontaktieren Sie uns:

Bitte senden Sie Ihre Vorschläge, Tippfehler, Fehler usw. sowie alle Fragen per E-Mail an: [email protected]