Защита от тёмных искусств
1. SQLite всегда проверяет свои входные данные
SQLite никогда не должен зависать, переполнять буфер, утечка памяти или проявлять любое другое вредное поведение, даже при представлении злонамеренно искажённых SQL-входных данных или баз данных. SQLite всегда должен обнаруживать ошибочные входные данные и генерировать ошибку, а не зависать или повреждать память. Любая неисправность, вызванная SQL-входом или файлом базы данных, считается серьёзной ошибкой и будет незамедлительно устранена при обращении к разработчикам SQLite. SQLite подвергается обширному тестированию на уязвимость, чтобы помочь гарантировать, что он устойчив к подобным ошибкам.
Тем не менее, ошибки случаются. Если вы разрабатываете приложение, которое отправляет недоверенные SQL-входные данные или файлы баз данных в SQLite, вы можете предпринять дополнительные шаги, чтобы уменьшить область атаки и предотвратить эксплойты нулевого дня, вызванные необнаруженными ошибками.
1.1. Недоверенные SQL-входные данные
Приложения, принимающие недоверенные SQL-входные данные, должны принять следующие меры предосторожности:
Установите флаг SQLITE_DBCONFIG_DEFENSIVE. Это предотвращает обычные SQL-запросы от преднамеренного повреждения файла базы данных. SQLite должен быть защищён от атак, которые включают как вредоносные SQL-входные данные, так и злонамеренно повреждённый файл базы данных одновременно. Тем не менее, отказ атакующему, использующему только скрипты, доступа к повреждению входных данных базы данных обеспечивает дополнительный уровень защиты.
-
Уменьшите пределы, которые SQLite накладывает на входные данные. Это может помочь предотвратить атаки типа "отказ в обслуживании" и другие виды злонамеренных действий, которые могут возникнуть в результате необычно больших входных данных. Вы можете сделать это либо во время компиляции, используя опции -DSQLITE_MAX_..., либо во время выполнения, используя интерфейс sqlite3_limit(). Большинство приложений могут значительно уменьшить пределы без влияния на функциональность. Нижеприведённая таблица содержит некоторые рекомендации, хотя точные значения будут варьироваться в зависимости от приложения:
Настройка предела Значение по умолчанию Значение высокой безопасности LIMIT_LENGTH 1 000 000 000 1 000 000 LIMIT_SQL_LENGTH 1 000 000 000 100 000 LIMIT_COLUMN 2000 100 LIMIT_EXPR_DEPTH 1000 10 LIMIT_COMPOUND_SELECT 500 3 LIMIT_VDBE_OP 250 000 000 25 000 LIMIT_FUNCTION_ARG 127 8 LIMIT_ATTACH 10 0 LIMIT_LIKE_PATTERN_LENGTH 50 000 50 LIMIT_VARIABLE_NUMBER 999 10 LIMIT_TRIGGER_DEPTH 1000 10 Рассмотрите возможность использования интерфейса sqlite3_set_authorizer() для ограничения области SQL, которая будет обработана. Например, приложение, которому не нужно изменять схему базы данных, может добавить обратный вызов sqlite3_set_authorizer(), который заставляет любой оператор CREATE или DROP завершиться ошибкой.
Язык SQL очень мощный, и поэтому всегда возможно, что вредоносные (или ошибочные, вызванные ошибкой приложения) SQL-входные данные отправят SQL, который будет выполняться очень долго. Чтобы предотвратить превращение этого в атаку типа "отказ в обслуживании", рассмотрите возможность использования интерфейса sqlite3_progress_handler(), чтобы периодически вызывать обратный вызов при выполнении каждого SQL-запроса, и указать этому обратному вызову возвращать ненулевое значение, чтобы прервать запрос, если он выполняется слишком долго. В качестве альтернативы можно установить таймер в отдельном потоке и вызвать sqlite3_interrupt(), когда таймер сработает, чтобы предотвратить выполнение SQL-запроса бесконечно.
Ограничьте максимальное количество памяти, которое SQLite будет выделять, используя интерфейс sqlite3_hard_heap_limit64(). Это помогает предотвратить атаки типа "отказ в обслуживании". Чтобы узнать, сколько места в куче фактически требуется приложению, запустите его с типичными входными данными, а затем измерьте максимальное мгновенное использование памяти с помощью интерфейса sqlite3_memory_highwater(). Установите жёсткий предел кучи на максимальное наблюдаемое мгновенное использование памяти плюс некоторый запас.
Рассмотрите возможность установки опции компиляции SQLITE_MAX_ALLOCATION_SIZE на значение, меньшее, чем её значение по умолчанию 2147483391 (0x7ffffeff). Значение 100 000 000 (100 миллионов) или даже меньшее было бы вполне разумным в зависимости от приложения.
-
Для встраиваемых систем рассмотрите компиляцию SQLite с опцией -DSQLITE_ENABLE_MEMSYS5, а затем предоставьте SQLite фиксированный блок памяти для использования в качестве кучи через интерфейс sqlite3_config(SQLITE_CONFIG_HEAP). Это предотвратит выполнение вредоносного SQL-запроса атаки типа "отказ в обслуживании" путём использования чрезмерного количества памяти. Если, скажем, для SQLite предоставлено 5 МБ памяти, то как только это количество будет использовано, SQLite начнёт возвращать ошибки SQLITE_NOMEM вместо поглощения памяти, необходимой другим частям приложения. Это также изолирует память SQLite, так что ошибка «запись после освобождения» в другой части приложения не вызовет проблем для SQLite, и наоборот.
-
Для управления использованием памяти в функции printf() SQL, скомпилируйте с "-DSQLITE_PRINTF_PRECISION_LIMIT=100000" или аналогичным разумным значением. Это #define ограничивает ширину и точность %-замещений в функции printf() и, таким образом, предотвращает выполнение злонамеренного SQL-запроса от потребления больших объёмов оперативной памяти с помощью конструкций, таких как "
printf('%1000000000s','hi')".Обратите внимание, что SQLite использует свою встроенную функцию printf() для форматирования столбца sql в таблице sqlite_schema. По этой причине ни одно определение таблицы, индекса, представления или триггера не может быть значительно больше, чем предел точности. Вы можете установить предел точности меньше 100 000, но будьте осторожны, что установленный вами предел точности по крайней мере равен длине самого длинного оператора CREATE в вашей схеме.
1.2. Недоверенные файлы баз данных SQLite
Приложения, которые читают или записывают файлы баз данных SQLite неизвестного происхождения, должны принять меры предосторожности, перечисленные ниже.
Даже если приложение не принимает намеренно файлы баз данных из недоверенных источников, будьте внимательны к атакам, в которых локальный файл базы данных изменяется. Для обеспечения максимальной безопасности любой файл базы данных, который когда-либо мог быть доступен для записи агентом в другой области безопасности, следует считать подозрительным.
-
Если приложение включает в себя какие-либо пользовательские SQL-функции или пользовательские виртуальные таблицы, которые имеют побочные эффекты или могут утекать привилегированную информацию, то приложение должно использовать один или несколько приведённых ниже методов для предотвращения того, чтобы злонамеренно составленная схема базы данных тайно запускала эти SQL-функции и/или виртуальные таблицы в корыстных целях:
- Вызовите sqlite3_db_config(db,SQLITE_DBCONFIG_TRUSTED_SCHEMA,0,0) для каждой подключения к базе данных сразу после её открытия.
- Запустите оператор PRAGMA trusted_schema=OFF для каждого подключения к базе данных сразу после её открытия.
- Скомпилируйте SQLite с опцией -DSQLITE_TRUSTED_SCHEMA=0 во время компиляции.
- Отключите тайную загрузку пользовательских SQL-функций и виртуальных таблиц, установив флаг SQLITE_DIRECTONLY для всех пользовательских SQL-функций и флаг SQLITE_VTAB_DIRECTONLY для всех пользовательских виртуальных таблиц.
-
Если приложение не использует триггеры или представления, рассмотрите возможность отключения неиспользуемых возможностей:
sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_TRIGGER,0,0); sqlite3_db_config(db,SQLITE_DBCONFIG_ENABLE_VIEW,0,0);
При чтении файлов баз данных, которые представляют собой повышенный риск, например, файлов баз данных, полученных с удалённых компьютеров, и, возможно, от анонимных авторов, могут быть оправданы следующие дополнительные меры предосторожности. Однако эти дополнительные меры защиты сопровождаются снижением производительности и поэтому могут не быть уместными в каждой ситуации:
Запустите PRAGMA integrity_check или PRAGMA quick_check для базы данных как первый SQL-запрос после открытия файлов базы данных и до выполнения других SQL-запросов. Отклоните и откажитесь обрабатывать любой файл базы данных, содержащий ошибки.
-
Включите настройку PRAGMA cell_size_check=ON.
Не включайте память-отображение ввода-вывода. Другими словами, убедитесь, что PRAGMA mmap_size=0.
2. Заключение
Перечисленные выше меры предосторожности не являются обязательными для безопасного использования SQLite с потенциально враждебными входными данными. Однако они обеспечивают дополнительный уровень защиты от эксплойтов нулевого дня и рекомендуются для приложений, которые передают данные из недоверенных источников в SQLite.
Эта страница была обновлена в 2024-01-16 14:06:27 UTC
SQLite is in the Public Domain.
https://sqlite.org/security.html