- PVSM.RU - https://www.pvsm.ru -

Простое шифрование БД SQlite

Простое шифрование БД SQlite - 1Так получилось, что я очень люблю использовать SQLite СУБД.

Программируя на ассемблере, я иногда нуждаюсь в полноценной СУБД. Мои программы редко превышают в размере несколько сотен килобайт. Понятно, что использовать с ним СУБД в несколько сотен мегабайт по меньшей мере просто смешно, а в конце концов, очень неудобно – сразу возрастают требования к оборудованию и сложности установки и настройки, а в итоге уменьшается надежность всей системы.

SQLite совершенно другое дело. Во-первых, она маленькая – всего несколько сот килобайт, прекрасное дополнение к компактным программам на ассемблере. Во-вторых, это ультра-надежная система хранения данных. Никаких специальных установок и настроек ей не нужно. Ну и насчет быстродействия – не из последних.

К примеру, я использовал SQLite в моем движке форума AsmBB [1] о котором уже писал [2] на Хабре. (Кстати, после этого он так и не упал [3]).

С того времени проект медленно, но уверенно развивается. Появились новые функции, повысились безопасность и быстродействие.

И вот однажды я задумался как повысить и так неплохую безопасность проекта. И сразу подумал, что неплохо было бы сделать шифрование БД форума. Ведь если даже база и утечёт, то доступ к личным данным пользователей никто не получит.

Быстрый поиск по Интернету показал, что есть несколько расширений SQLite для шифрования БД. К сожалению, официальное расширение SEE [4] несвободно и вообще продается за деньги.

Но, конечно, свято место пусто не бывает и я сразу наткнулся на расширение SQLeet [5]. И в нем мне понравилось буквально все.

SQLeet использует алгоритм ChaCha20 для шифрования БД. Ключ шифрования вычисляется через PBKDF2-HMAC-SHA256, используя 16-байтовую соль и 12345 итераций хеширования. Для аутентификации используется Poly1305.

И SQLeet и SQLite распространяются на условиях общественного достояния (public domain). Это удобно, так как не увеличивает лицензионный хаос в проекте.

Еще SQLeet очень компактный. Весь код занимает только около полутора тысяч строк на C и не имеет внешних зависимостей.

Проект активно поддерживается и автор оперативно отвечает на вопросы и исправляет баги, если такие найдутся.

SQLeet распространяется тем же самым образом, как и SQLite – в форме единственного исходного файла на C, который можно просто скомпилировать тем же самым образом как компилируется и SQLite.

К тому же, так как расширение никак не меняет код SQLite, то обновления основной СУБД можно делать очень просто – через замены файла sqlite3.c и пересоздание объединенного исходника.

Так как в AsmBB я использую не совсем стандартную компиляцию (SQLite в AsmBB компилируется через MUSL libc [6]), а я не являюсь C программистом, то для меня простота компиляции очень важна.

Вот, например, баш код, который я использую, чтобы скачать последнюю версию SQLeet и создать и скомпоновать исходник:

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/

В результате получается файл sqlite3.c который можно вставить там, где раньше вставлялся оригинальный файл SQLite и использовать тем же образом.

Использование расширения тоже никак не отличается от использования SQLite. Разница только в том, что если БД зашифрована, то сразу после открытия надо вызвать функцию sqlite3_key(), в которой указать пароль шифрования. Ну или даже лучше, просто исполнить SQL pragma key='%пароль%'. (Это лучше потому что API интерфейс к SQLite не меняется и
всегда можно заменить SQLeet на SQLite и обратно).

Начальное шифрование БД, а также замена пароля, происходит через функцию sqlite3_rekey() или pragma командой pragma rekey='%NEW_PASSWORD%'.

И вот здесь у меня возник такой вопрос. Откуда вообще брать пароль? Ведь если пароль сохраняется на сервере в каком-нибудь файле, то потенциальный хакер сможет прочесть его.

Поэтому я решил сделать по-другому. Дело в том, что AsmBB является долгоживущим FastCGI приложением. Однажды запущенный на сервере, он работает месяцы и даже годы без необходимости в перезагрузке.

А раз так, то пароль просто может ввести администратор через веб-интерфейс сразу после запуска AsmBB. Таким образом, пароль существует только в RAM и только во время исполнения POST-запроса во время запуска приложения. (Конечно, не надо забывать затирать нулями всю память, в которой пароль существовал во время исполнения POST-запроса.)

Из заданного пароля SQLeet генерирует ключ шифрования через PBKDF2-HMAC-SHA256, и этот ключ тоже хранится только в RAM.

Конечно, такое решение несовершенно. Ключ шифрования, наверное, можно найти в RAM памяти, во время исполнения AsmBB, если у атакующего есть права администратора.

Но даже если и так, то система все равно получается намного безопаснее, чем без шифровки. Например, теперь резервные копии БД можно хранить вообще повсюду и пересылать по открытым каналам, не опасаясь утечки данных.

Есть, кстати, и грабли, на которые можно наступить, применяя SQLeet (или другие криптографические расширения SQLite). И я на них, конечно, наступил.

Проблема в размере страницы БД. В версиях SQLite более ранних, чем 3.12.0 (март 2016 года) дефолтный размер страницы был 1024 байта. В v3.12.0 его сделали 4096 байта. Этот размер, пользователь БД может менять из соображений производительности, а размер страницы записан в самой БД.

Но если БД зашифрована, то размер страницы нельзя прочесть, а для расшифровки этот размер нужен, потому что каждый блок зашифровывается отдельно.

Поэтому, если зашифровать БД с нестандартным размером страницы (для SQLeet стандарт 4096 байт), потом расшифровать не удастся, даже если задавать правильный пароль.

Исправляется это просто – прежде, чем задавать пароль через sqlite3_key() или pragma key='%пароль%', надо задать правильный размер страницы через pragma page_size=%размер%.

Другая возможная проблема в том, что после шифровки ОС уже не сможет распознать, что файл является SQLite БД. Это (насколько я читал) иногда приводит к каким-то проблемам, в частности в iOS. Решение этой проблемы есть, просто не шифровать первые 32 байта файла, но в детали я не вдавался.

И напоследок насчет производительности. SQLeet работает очень быстро. После шифрования я не заметил какого-либо замедления работы системы на фоне нормальных флуктуаций производительности VPS [7]. Прецизионные измерения, возможно, покажут какое-нибудь замедление, но оно наверняка будет в пределах меньше чем 10% от скорости не зашифрованной БД.

Конечно, есть и другие свободные расширения SQLite для шифрования. Например, SQLcipher [8]. Мне оно не подошло потому что у него другая лицензия распространения (BSD), намного больше размер кода и имеются внешние зависимости.

Но, с другой стороны, SQLcipher намного старше и поэтому (возможно) более стабильный. Кому-то может и пригодится.

Автор: John Found

Источник [9]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/kriptografiya/332361

Ссылки в тексте:

[1] AsmBB: https://board.asm32.info

[2] уже писал: https://habr.com/ru/post/318916/

[3] не упал: https://habr.com/ru/post/319028/

[4] SEE: https://www.hwaci.com/sw/sqlite/see.html

[5] SQLeet: https://github.com/resilar/sqleet

[6] MUSL libc: https://www.musl-libc.org/

[7] VPS: https://www.reg.ru/?rlink=reflink-717

[8] SQLcipher: https://github.com/sqlcipher/sqlcipher

[9] Источник: https://habr.com/ru/post/470295/?utm_source=habrahabr&utm_medium=rss&utm_campaign=470295