Einfache SQlite DB-Verschlüsselung

Es ist so passiert, dass ich SQLite DBMS wirklich gerne benutze.


Beim Programmieren in Assembler benötige ich manchmal ein vollständiges DBMS. Meine Programme überschreiten selten einige hundert Kilobyte. Es ist klar, dass die Verwendung eines DBMS von mehreren hundert Megabyte damit zumindest lächerlich, aber letztendlich sehr unpraktisch ist - die Hardwareanforderungen und die Komplexität der Installation und Konfiguration steigen sofort, und infolgedessen nimmt die Zuverlässigkeit des gesamten Systems ab.


SQLite ist eine ganz andere Sache. Erstens ist es klein - nur ein paar hundert Kilobyte, eine großartige Ergänzung zu kompakten Assembler-Programmen. Zweitens ist es ein äußerst zuverlässiges Datenspeichersystem. Sie benötigt keine speziellen Einstellungen und Einstellungen. Nun, was die Leistung betrifft - nicht die letzte.


Zum Beispiel habe ich SQLite in meiner AsmBB- Forum- Engine verwendet, über die ich bereits über Habré geschrieben habe. (Übrigens ist er danach nicht gefallen ).


Seitdem hat sich das Projekt langsam aber sicher weiterentwickelt. Es sind neue Funktionen erschienen, die die Sicherheit und Leistung erhöhen.


Und dann dachte ich eines Tages darüber nach, wie ich die ohnehin schon gute Sicherheit des Projekts erhöhen könnte. Und ich dachte sofort, dass es schön wäre, die Forendatenbank zu verschlüsseln. Selbst wenn die Datenbank durchgesickert ist, erhält niemand Zugriff auf die persönlichen Daten der Benutzer.


Eine schnelle Suche im Internet ergab, dass es mehrere SQLite-Erweiterungen für die Datenbankverschlüsselung gibt. Leider ist die offizielle SEE- Erweiterung nicht kostenlos und wird in der Regel für Geld verkauft.


Aber natürlich ist ein heiliger Ort niemals leer und ich bin sofort auf die SQLeet- Erweiterung gestoßen . Und darin gefiel mir buchstäblich alles.


SQLeet verwendet den ChaCha20-Algorithmus, um die Datenbank zu verschlüsseln. Der Verschlüsselungsschlüssel wird über PBKDF2-HMAC-SHA256 unter Verwendung eines 16-Byte-Salt- und 12345-Hash-Iterationen berechnet. Zur Authentifizierung wird Poly1305 verwendet.


Sowohl SQLeet als auch SQLite werden unter der Public Domain (Public Domain) verteilt. Dies ist praktisch, da es das Lizenzierungschaos im Projekt nicht erhöht.


Trotzdem ist SQLeet sehr kompakt. Der gesamte Code benötigt in C nur etwa anderthalb Tausend Zeilen und weist keine externen Abhängigkeiten auf.


Das Projekt wird aktiv unterstützt und der Autor beantwortet umgehend Fragen und behebt etwaige Fehler.


SQLeet wird auf die gleiche Weise wie SQLite verteilt - in Form einer einzelnen C-Quelldatei, die Sie einfach auf die gleiche Weise kompilieren können wie SQLite.


Da die Erweiterung den SQLite-Code in keiner Weise ändert, kann das Haupt-DBMS außerdem sehr einfach aktualisiert werden, indem die Datei sqlite3.c und die kombinierte Quelle neu erstellt wird.


Da ich in AsmBB keine Standardkompilierung verwende (SQLite in AsmBB wird über MUSL libc kompiliert) und kein C-Programmierer bin, ist für mich die Einfachheit der Kompilierung sehr wichtig.


Hier ist beispielsweise der Bash-Code, mit dem ich die neueste Version von SQLeet herunterlade und die Quelle erstelle und erstelle:


 wget -q -O - https://github.com/resilar/sqleet/archive/master.tar.gz | tar -xz cd ./sqleet-master script/amalgamate.sh < ./sqleet.c > ../sqlite3.c cd .. rm -rf ./sqleet-master/ 

Das Ergebnis ist eine sqlite3.c Datei, die dort eingefügt werden kann, wo die ursprüngliche SQLite-Datei zuvor eingefügt und auf die gleiche Weise verwendet wurde.


Die Verwendung der Erweiterung unterscheidet sich auch nicht von der Verwendung von SQLite. Der einzige Unterschied besteht darin, dass bei einer Verschlüsselung der Datenbank unmittelbar nach dem Öffnen die Funktion sqlite3_key () aufgerufen werden muss, in der Sie das Verschlüsselungskennwort angeben. Nun, oder noch besser, führen Sie einfach SQL pragma key='%%' . (Dies ist besser, da sich die SQLite-API nicht ändert und
Sie können SQLeet jederzeit durch SQLite ersetzen und umgekehrt.


Die anfängliche Datenbankverschlüsselung sowie das Ersetzen des Kennworts erfolgt über die Funktion sqlite3_rekey() oder das Pragma mit dem pragma rekey='%NEW_PASSWORD%' .


Und hier hatte ich so eine Frage. Woher kommt das Passwort? Wenn das Kennwort in einer Datei auf dem Server gespeichert ist, kann der potenzielle Hacker es schließlich lesen.


Also habe ich beschlossen, es anders zu machen. Tatsache ist, dass AsmBB eine langlebige FastCGI-Anwendung ist. Einmal auf einem Server gestartet, läuft es Monate und sogar Jahre, ohne dass ein Neustart erforderlich ist.


In diesem Fall kann der Administrator das Kennwort unmittelbar nach dem Start von AsmBB einfach über die Weboberfläche eingeben. Daher ist das Kennwort nur im RAM und nur während der Ausführung der POST-Anforderung während des Anwendungsstarts vorhanden. (Vergessen Sie natürlich nicht, den gesamten Speicher, in dem das Kennwort vorhanden war, während der Ausführung der POST-Anforderung auf Null zu setzen.)


Aus dem festgelegten Kennwort generiert SQLeet über PBKDF2-HMAC-SHA256 einen Verschlüsselungsschlüssel, der ebenfalls nur im RAM gespeichert wird.


Natürlich ist eine solche Entscheidung unvollkommen. Der Verschlüsselungsschlüssel befindet sich wahrscheinlich während der Ausführung von AsmBB im RAM-Speicher, wenn der Angreifer über Administratorrechte verfügt.


Trotzdem ist das System immer noch viel sicherer als ohne Verschlüsselung. Beispielsweise können jetzt Datenbanksicherungen überall gespeichert und über offene Kanäle gesendet werden, ohne dass Datenlecks befürchtet werden.


Übrigens gibt es einen Rechen, auf den Sie mit SQLeet (oder anderen kryptografischen SQLite-Erweiterungen) zugreifen können. Und ich bin natürlich auf sie getreten.


Das Problem ist die Größe der Datenbankseite. In früheren SQLite-Versionen als 3.12.0 (März 2016) betrug die Standardseitengröße 1024 Byte. In Version 3.12.0 haben es 4096 Bytes geschafft. Diese Größe kann der Datenbankbenutzer aus Leistungsgründen ändern, und die Seitengröße wird in die Datenbank selbst geschrieben.


Wenn die Datenbank jedoch verschlüsselt ist, kann die Seitengröße nicht gelesen werden. Für die Entschlüsselung wird diese Größe benötigt, da jeder Block separat verschlüsselt wird.


Wenn Sie eine Datenbank mit einer nicht standardmäßigen Seitengröße verschlüsseln (für SQLeet beträgt der Standard 4096 Byte), können Sie sie daher nicht entschlüsseln, selbst wenn Sie das richtige Kennwort festgelegt haben.


Dies wird einfach behoben - bevor Sie das Passwort über sqlite3_key() oder pragma key='%%' festlegen, müssen Sie die richtige Seitengröße über pragma page_size=%% .


Ein weiteres mögliches Problem besteht darin, dass das Betriebssystem nach der Verschlüsselung nicht mehr erkennen kann, dass es sich bei der Datei um eine SQLite-Datenbank handelt. Dies führt (soweit ich lese) manchmal zu Problemen, insbesondere bei iOS. Es gibt eine Lösung für dieses Problem. Verschlüsseln Sie einfach nicht die ersten 32 Bytes der Datei, aber ich habe nicht auf Details eingegangen.


Und schließlich zur Leistung. SQLeet ist sehr schnell. Nach der Verschlüsselung habe ich vor dem Hintergrund normaler Schwankungen der VPS-Leistung keine Verlangsamung des Systems festgestellt. Präzisionsmessungen können eine gewisse Verlangsamung anzeigen, liegen jedoch wahrscheinlich innerhalb von weniger als 10% der Geschwindigkeit einer unverschlüsselten Datenbank.


Natürlich gibt es auch andere kostenlose SQLite-Erweiterungen für die Verschlüsselung. Zum Beispiel SQLcipher . Es hat mir nicht gepasst, weil es eine andere Distributionslizenz (BSD) hat, der Code viel größer ist und es externe Abhängigkeiten gibt.


Andererseits ist SQLcipher viel älter und daher (möglicherweise) stabiler. Jemand kann nützlich sein.

Source: https://habr.com/ru/post/de470295/


All Articles