Лучшие практики защиты SQLite

Fri Nov 21 2025

Это руководство представляет собой краткий практический чек-лист для усиления защиты 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 rekey SQLCipher во время окна обслуживания

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 и имеет доступ к файловой системе с минимальными привилегиями