Cryptage SQlite DB simple

Il se trouve que j'aime vraiment utiliser le SGBD SQLite.


Lors de la programmation en assembleur, j'ai parfois besoin d'un SGBD complet. Mes programmes dépassent rarement quelques centaines de kilo-octets. Il est clair que l'utilisation d'un SGBD de plusieurs centaines de mégaoctets avec lui est au moins ridicule, mais finalement très gênant - les exigences matérielles et la complexité de l'installation et de la configuration augmentent immédiatement, et par conséquent, la fiabilité de l'ensemble du système diminue.


SQLite est une affaire complètement différente. Tout d'abord, il est petit - seulement quelques centaines de kilo-octets, un excellent ajout aux programmes d'assemblage compacts. Deuxièmement, c'est un système de stockage de données ultra-fiable. Elle n'a pas besoin de paramètres et de paramètres spéciaux. Eh bien, en ce qui concerne les performances - pas le dernier.


Par exemple, j'ai utilisé SQLite dans mon moteur de forum AsmBB sur lequel j'ai déjà écrit sur Habré. (Au fait, après cela, il n'est pas tombé ).


Depuis lors, le projet se développe lentement mais sûrement. De nouvelles fonctionnalités sont apparues, une sécurité et des performances accrues.


Et puis un jour j'ai réfléchi à comment augmenter la sécurité déjà bonne du projet. Et j'ai tout de suite pensé qu'il serait bien de crypter la base de données du forum. En effet, même en cas de fuite de la base de données, personne n'aura accès aux données personnelles des utilisateurs.


Une recherche rapide sur Internet a montré qu'il existe plusieurs extensions SQLite pour le chiffrement de la base de données. Malheureusement, l'extension officielle SEE n'est pas gratuite et généralement vendue pour de l'argent.


Mais, bien sûr, un lieu saint n'est jamais vide et je suis immédiatement tombé sur l'extension SQLeet . Et j'y ai littéralement tout aimé.


SQLeet utilise l'algorithme ChaCha20 pour crypter la base de données. La clé de chiffrement est calculée via PBKDF2-HMAC-SHA256 en utilisant un sel de 16 octets et des itérations de hachage 12345. Pour l'authentification, Poly1305 est utilisé.


SQLeet et SQLite sont distribués sous le domaine public (domaine public). C'est pratique car cela n'augmente pas le chaos des licences dans le projet.


SQLeet est toujours très compact. Tout le code ne prend qu'environ mille et demi de lignes en C et n'a pas de dépendances externes.


Le projet est activement soutenu et l'auteur répond rapidement aux questions et corrige les bogues, le cas échéant.


SQLeet est distribué de la même manière que SQLite - sous la forme d'un seul fichier source C que vous pouvez simplement compiler de la même manière que SQLite.


De plus, comme l'extension ne modifie en rien le code SQLite, la mise à jour du SGBD principal peut être effectuée très simplement - en remplaçant le fichier sqlite3.c et en recréant la source combinée.


Comme j'utilise une compilation pas tout à fait standard dans AsmBB (SQLite dans AsmBB est compilé via MUSL libc ), et je ne suis pas un programmeur C, pour moi la simplicité de la compilation est très importante.


Par exemple, voici le code bash que j'utilise pour télécharger la dernière version de SQLeet et créer et générer la source:


 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/ 

Le résultat est un fichier sqlite3.c qui peut être inséré là où le fichier SQLite d'origine a été inséré avant et utilisé de la même manière.


L'utilisation de l'extension n'est pas différente de l'utilisation de SQLite. La seule différence est que si la base de données est cryptée, immédiatement après son ouverture, il est nécessaire d'appeler la fonction sqlite3_key (), dans laquelle vous spécifiez le mot de passe de cryptage. Eh bien, ou mieux encore, exécutez simplement SQL pragma key='%%' . (C'est mieux parce que l'API SQLite ne change pas et
vous pouvez toujours remplacer SQLeet par SQLite et vice versa).


Le chiffrement initial de la base de données, ainsi que le remplacement du mot de passe, se produisent via la fonction sqlite3_rekey() ou pragma avec la commande pragma rekey='%NEW_PASSWORD%' .


Et ici, j'avais une telle question. D'où vient le mot de passe? Après tout, si le mot de passe est stocké sur le serveur dans un fichier, le pirate potentiel pourra le lire.


J'ai donc décidé de le faire différemment. Le fait est que AsmBB est une application FastCGI à longue durée de vie. Une fois lancé sur un serveur, il fonctionne pendant des mois et même des années sans avoir besoin d'un redémarrage.


Et si c'est le cas, l'administrateur peut simplement saisir le mot de passe via l'interface Web immédiatement après le démarrage d'AsmBB. Ainsi, le mot de passe n'existe que dans la RAM et uniquement lors de l'exécution de la requête POST lors du lancement de l'application. (Bien sûr, n'oubliez pas de remettre à zéro toute la mémoire dans laquelle le mot de passe existait lors de l'exécution de la requête POST.)


À partir du mot de passe défini, SQLeet génère une clé de chiffrement via PBKDF2-HMAC-SHA256, et cette clé est également stockée uniquement dans la RAM.


Bien sûr, une telle décision est imparfaite. La clé de chiffrement peut probablement être trouvée dans la mémoire RAM, lors de l'exécution de AsmBB, si l'attaquant a des droits d'administrateur.


Mais même ainsi, le système est encore beaucoup plus sûr que sans cryptage. Par exemple, les sauvegardes de bases de données peuvent désormais être stockées partout et envoyées sur des canaux ouverts sans crainte de fuite de données.


Soit dit en passant, il existe un râteau sur lequel vous pouvez utiliser SQLeet (ou d'autres extensions cryptographiques SQLite). Et moi, bien sûr, j'ai marché dessus.


Le problème est la taille de la page de la base de données. Dans les versions de SQLite antérieures à 3.12.0 (mars 2016), la taille de page par défaut était de 1024 octets. Dans v3.12.0, 4096 octets l'ont fait. Cette taille, l'utilisateur de la base de données peut changer pour des raisons de performances, et la taille de la page est écrite dans la base de données elle-même.


Mais si la base de données est chiffrée, la taille de la page ne peut pas être lue, et pour le déchiffrement, cette taille est nécessaire, car chaque bloc est chiffré séparément.


Par conséquent, si vous cryptez une base de données avec une taille de page non standard (pour SQLeet, la norme est de 4096 octets), vous ne pourrez pas la décrypter, même si vous définissez le mot de passe correct.


Ceci est résolu simplement - avant de définir le mot de passe via sqlite3_key() ou pragma key='%%' , vous devez définir la taille de page correcte via pragma page_size=%% .


Un autre problème possible est qu'après le cryptage, le système d'exploitation ne pourra plus reconnaître que le fichier est une base de données SQLite. Cela (pour autant que je sache) entraîne parfois des problèmes, en particulier dans iOS. Il existe une solution à ce problème, il suffit de ne pas chiffrer les 32 premiers octets du fichier, mais je ne suis pas entré dans les détails.


Et enfin, sur les performances. SQLeet est très rapide. Après le cryptage, je n'ai remarqué aucun ralentissement du système dans le contexte de fluctuations normales des performances VPS. Les mesures de précision peuvent montrer une sorte de ralentissement, mais elles seront probablement inférieures à 10% de la vitesse d'une base de données non chiffrée.


Bien sûr, il existe d'autres extensions SQLite gratuites pour le chiffrement. Par exemple, SQLcipher . Cela ne me convenait pas car il a une licence de distribution différente (BSD), le code est beaucoup plus volumineux et il existe des dépendances externes.


Mais, d'autre part, SQLcipher est beaucoup plus ancien et donc (éventuellement) plus stable. Quelqu'un peut être utile.

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


All Articles