Это руководство представляет собой краткий практический чек-лист для усиления защиты SQLite в приложениях и сервисах. В нём основное внимание уделено реальным шагам, которые можно применить уже сегодня, с фрагментами кода, готовыми для копирования и вставки.
Краткий чек-лист
- Шифруйте данные в состоянии покоя с помощью SQLCipher (или SEE); никогда не храните базы данных в открытом виде
- Храните ключи в secrets manager; выполняйте ротацию и избегайте жёсткого кодирования
- Используйте разрешения только для владельца для файлов БД/журнала/WAL (
chmod 600), размещайте их в закрытых каталогах - Используйте параметризованные запросы для предотвращения SQL-инъекций
- Предпочитайте
journal_mode=WAL,synchronous=FULL,foreign_keys=ON - Рассмотрите
secure_delete=ONдля удаления конфиденциальных данных; используйтеtemp_store=MEMORY, чтобы уменьшить следы на диске - Отключите загрузку расширений; по возможности используйте соединения только для чтения/только для запросов
- Создавайте резервные копии безопасным способом (с шифрованием), тестируйте восстановление и удаляйте открытые копии
- Запускайте приложение от имени пользователя без прав root; ограничьте доступ к файловой системе
1) Шифруйте базу данных в состоянии покоя (SQLCipher)
Сам SQLite не имеет встроенного шифрования. Используйте SQLCipher (с открытым исходным кодом) или SEE (коммерческий продукт), чтобы зашифровать всю базу данных, включая страницы, WAL и журналы.
Установка (пример для macOS):
brew install sqlcipher
Инициализация или открытие зашифрованной БД:
PRAGMA key = 'your strong passphrase here';
-- Optional: set KDF iteration count and cipher settings per SQLCipher docs
-- PRAGMA kdf_iter = 256000;
-- PRAGMA cipher_page_size = 4096;
Пример на Python:
# pip install pysqlcipher3
import sqlite3
from pysqlcipher3 import dbapi2 as sqlcipher
conn = sqlcipher.connect("app.db")
cur = conn.cursor()
cur.execute("PRAGMA key = ?;", ("env_or_secret_manager_key",))
cur.execute("CREATE TABLE IF NOT EXISTS notes(id INTEGER PRIMARY KEY, body TEXT);")
conn.commit()
Советы по ключам:
- Парольная фраза должна поступать из secrets manager или хранилища ключей ОС (а не из кода)
- Выполняйте ротацию ключей с помощью
PRAGMA rekeySQLCipher во время окна обслуживания
2) Безопасно управляйте ключами
- Храните ключи в secrets manager (AWS Secrets Manager, GCP Secret Manager, Vault)
- Передавайте их через переменные окружения или защищённые файлы, владельцем которых является пользователь приложения
- Выполняйте ротацию по расписанию и при увольнении сотрудников; отслеживайте неправомерное использование ключей
.env (только для разработки):
SQLCIPHER_KEY="change-me"
3) Ограничьте разрешения и расположение файлов
SQLite записывает несколько файлов: основной .db, а также -wal и -shm, когда включён WAL. Все они должны быть защищены.
# Run your app as its own user; restrict ownership and permissions
chown appuser:appuser app.db*
chmod 600 app.db*
umask 077
Рекомендации:
- Размещайте файлы БД в закрытом каталоге, не предназначенном для общего доступа
- Избегайте путей, доступных для чтения всем пользователям (например,
/tmpили общих томов) - На мобильных устройствах отключите системное резервное копирование данных приложения, если БД содержит конфиденциальные данные
4) Предотвращайте SQL-инъекции с помощью параметризованных запросов
Никогда не объединяйте пользовательский ввод со строкой SQL. Используйте параметры в каждом запросе.
Python:
cur.execute("SELECT * FROM users WHERE email = ?", (email,))
Node (better-sqlite3):
db.prepare("INSERT INTO notes (body) VALUES (?)").run(body);
5) Более безопасные настройки PRAGMA по умолчанию для безопасности и надёжности
Устанавливайте эти параметры после открытия каждого соединения (или через хуки вашего ORM/драйвера):
PRAGMA foreign_keys = ON; -- enforce referential integrity
PRAGMA journal_mode = WAL; -- better durability and concurrency
PRAGMA synchronous = FULL; -- stronger crash safety for WAL
PRAGMA temp_store = MEMORY; -- reduce sensitive temp files on disk
PRAGMA secure_delete = ON; -- overwrite deleted content (perf trade-off)
Примечания:
secure_delete=ONувеличивает нагрузку на запись; включайте этот параметр, если важна защита остатков данныхtemp_store=MEMORYувеличивает использование RAM; учитывайте это при планировании ресурсов
Соединения только для чтения или только для запросов снижают риски для сервисов, которым нужны только операции чтения:
PRAGMA query_only = ON; -- disallow writes for this connection
6) Отключите загрузку расширений
Заблокируйте загрузку произвольных расширений, чтобы уменьшить поверхность атаки.
Python:
conn.enable_load_extension(False)
C:
sqlite3_enable_load_extension(db, 0);
7) Резервные копии и миграции без утечек
- Храните резервные копии в зашифрованном виде; не создавайте дампы в открытом виде
- Используйте
VACUUM INTOдля атомарного экспорта копии (SQLCipher поддерживает зашифрованные копии, если задан ключ)
-- Plain SQLite
VACUUM INTO 'backup.sqlite';
-- SQLCipher: set key on the new file first (see SQLCipher docs)
-- PRAGMA key = 'current_key';
-- PRAGMA cipher_export = 'encrypted.sqlite';
-- SELECT sqlcipher_export('main');
Операционные советы:
- Убедитесь, что хранилище резервных копий контролируется по доступу и зашифровано
- Регулярно тестируйте процедуры восстановления
- Удаляйте старые открытые копии и временные файлы экспорта
8) Усиление защиты ОС и контейнеров
- Запускайте приложение от имени пользователя без прав root; применяйте принцип минимальных привилегий для доступа к файловой системе
- Используйте полное шифрование диска на серверах и ноутбуках; отдавайте предпочтение зашифрованным томам
- Ограничивайте процесс с помощью AppArmor/SELinux, если они доступны
- Отслеживайте неожиданные чтения каталога БД
9) Наблюдаемость и сигналы целостности
- Регистрируйте события открытия/закрытия БД, неудачной аутентификации и операций миграции (без секретов)
- Отслеживайте хэши и размеры файлов для обнаружения неожиданных изменений
- Настройте оповещения об изменении разрешений (например, если файлы больше не имеют разрешений
0600)
Итоговый чек-лист
- Используется SQLCipher (или SEE); ключи поступают из secrets manager/хранилища ключей ОС
- Для файлов
.db,-wal,-shmустановлены разрешения только для владельца - Запросы параметризованы; SQL не формируется конкатенацией строк
-
foreign_keys=ON,journal_mode=WAL,synchronous=FULL,temp_store=MEMORY -
secure_delete=ON, если важна защита при удалении конфиденциальных данных - Загрузка расширений отключена; где применимо, используются соединения только для чтения/только для запросов
- Резервные копии зашифрованы; восстановление протестировано; старые открытые копии удалены
- Приложение работает без прав root и имеет доступ к файловой системе с минимальными привилегиями