Как стать автором
Обновить

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

Время на прочтение 4 мин
Количество просмотров 17K

Так получилось, что я очень люблю использовать SQLite СУБД.


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


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


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


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


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


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


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


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), а я не являюсь 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. Прецизионные измерения, возможно, покажут какое-нибудь замедление, но оно наверняка будет в пределах меньше чем 10% от скорости не зашифрованной БД.


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


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

Теги:
Хабы:
+22
Комментарии 5
Комментарии Комментарии 5

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн