![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
Приложения, которые используют SQLite, могут определить свои
функции SQL, которые обращаются в код приложения, чтобы вычислить
их результаты. Реализации функции SQL могут быть включены в сам код
приложения или могут быть
загружаемыми расширениями. Определенные применением функции SQL создаются, используя интерфейс
sqlite3_create_function().
Функции SQL могут быть скалярными функциями, агрегатными функциями или
функциями окна.
У функций SQL может быть любое количество аргументов от 0 до
SQLITE_MAX_FUNCTION_ARG.
Интерфейс sqlite3_create_function()
определяет отзывы, которые призваны, чтобы выполнить обработку для
новой функции SQL. SQLite также поддерживает табличные функции
, но они осуществляются иным механизмом, который
не охвачен в этом документе. Интерфейс sqlite3_create_function()
используется, чтобы создать новые функции SQL. Каждый член этого
интерфейса это обертка вокруг общего ядра. Все члены
достигают того же самого, у них просто есть различные сигнатуры запроса. sqlite3_create_function()
→ исходная версия sqlite3_create_function() позволяет
создать единственную новую функцию SQL, которая может быть скаляром или
совокупностью. Название функции определяется, используя UTF8. sqlite3_create_function16()
→ Этот вариант работает точно как оригинальный
sqlite3_create_function() за исключением того, что название самой функции
определяется как последовательность UTF16, а не
как последовательность UTF8. sqlite3_create_function_v2()
→ Этот вариант работает как оригинальный
sqlite3_create_function() за исключением того, что это включает
дополнительный параметр, который является указателем на деструктор для
указателя sqlite3_user_data(),
который передается как 5-й аргумент всем вариантам sqlite3_create_function().
Та функция деструктора (если это не NULL) вызвана, когда функция удалена:
обычно когда соединение с базой данных закрывается.
sqlite3_create_window_function() →
Этот вариант работает как оригинальный sqlite3_create_function()
за исключением того, что это принимает различный набор указателей отзыва:
указатели отзыва, используемые определениями
функции окна. Многие параметры, переданные к
sqlite3_create_function(), распространены для всего интерфейса. db → 1-й параметр всегда является указателем на
соединение с базой данных с
которым будет работать функция SQL. Функции SQL создаются отдельно для
каждого соединения с базой данных. Нет никакого механизма для создания
функций SQL, которые работают через все соединения с базой данных. zFunctionName → 2-й параметр название функции SQL, которая
создается. Имя обычно находится в UTF8, за исключением того, что имя должно
быть в UTF16 в родном порядке байтов для
sqlite3_create_function16(). Максимальная длина имени функции SQL составляет 255 байтов UTF8. Любая
попытка создать функцию с более длинным именем приведет к ошибке
SQLITE_MISUSE. Интерфейсы создания функции SQL можно вызвать многократно с тем же самым
именем функции. Если у двух требований будет тот же самый номер функции,
но различное количество аргументов, то два варианта функции SQL будут
зарегистрированы, каждый берет различное количество аргументов. nArg → 3-й параметр всегда это количество аргументов,
которое функция принимает. Значение должно быть целым числом между -1 и
SQLITE_MAX_FUNCTION_ARG
(по умолчанию: 127). Значение -1 указывает, что функция SQL это функция
variadic, которая может взять любое количество аргументов между 0 и
SQLITE_MAX_FUNCTION_ARG. eTextRep → 4-й параметр это 32-битный флаг целого числа,
биты которого передают различные свойства новой функции.
Оригинальная цель этого параметра состояла в том, чтобы определить
предпочтительное текстовое кодирование для функции, используя одну
из следующих констант: 4-й параметр позже был расширен дополнительными флаговыми битами, чтобы
передать дополнительную информацию о функции.
Дополнительные биты включают: Дополнительные биты могут быть добавлены в будущих версиях SQLite. pApp → 5-й параметр это произвольный указатель,
который передается в установленный порядок отзыва. Сам SQLite ничего не
делает с этим указателем, кроме как делает его доступным для отзывов и
передает его в деструктор, когда функция не зарегистрирована. Можно неоднократно вызвать sqlite3_create_function() для той же самой
функции SQL. Например, если функция SQL может взять 2 или 3 аргумента, то
sqlite3_create_function() была бы вызвана однажды для версии с 2 аргументами
и во второй раз для версии с 3 аргументами. Конкретная реализация (отзывы)
может отличаться для обоих вариантов. Применение может также зарегистрировать многократные функции SQL с тем же
самым именем и тем же самым количеством аргументов, но различным
предпочтительным текстовом кодировании. В этом случае SQLite вызовет функцию,
используя отзывы для версии, предпочтительный текст которой, кодирующий
наиболее тесно, соответствует текстовому кодированию базы данных.
Таким образом многократные внедрения той же самой функции могут состоять в
том, что они оптимизированы для UTF8 или UTF16. Если множественные вызовы sqlite3_create_function()
определяют то же самое имя функции, то же самое количество аргументов и то же
самое предпочтительное текстовое кодирование, то отзывы и другие параметры
второго вызова переписывают первый, и выполнен отзыв деструктора от первого
вызова (если это существует). SQLite оценивает функцию SQL, вызывая установленный порядок отзыва. Скалярные функции SQL осуществляются единственным отзывом в параметре
xFunc sqlite3_create_function(). Следующий код показывает
скалярную функцию SQL "noop(X)", которая просто возвращает ее аргумент: 1-й параметр context является указателем на
непрозрачный объект, который описывает содержание, из которого была вызвана
функция SQL. Этот пункт контекста становится первым параметром многих других
вызываемых функций, включая:
Интерфейс sqlite3_result()
используется, чтобы определить результат скалярной функции SQL. Одна или
больше из них должна быть вызвана отзывом, чтобы установить возвращаемое
значение функции. Если ни одна не будет вызвана для определенного отзыва,
то возвращаемым значением будет NULL. sqlite3_user_data()
возвращает копию указателя pArg, которая была дана
sqlite3_create_function(), когда
функция SQL была создана. sqlite3_context_db_handle()
возвращает указатель на объект
соединения с базой данных. sqlite3_aggregate_context()
используется только во внедрениях функций окна и совокупности.
Скалярные функции не могут использовать
sqlite3_aggregate_context().
Функция sqlite3_aggregate_context()
включена в интерфейсный список только для полноты. 2 и 3 аргументами скалярной функции SQL, argc и argv
является количество аргументов самой функции SQL и значений для каждого
аргумента функции SQL. Значения аргументов могут иметь любой тип данных и
таким образом сохранены в экземплярах объекта
sqlite3_value. Определенные значения языка
C могут быть извлечены из этого объекта, используя
sqlite3_value().
Совокупные функции SQL осуществляются при помощи двух функций обратного
вызова: xStep и xFinal. xStep() вызвана для каждой строки
совокупности, а xFinal() вызвана, чтобы вычислить окончательный ответ в
конце. Следующая (немного упрощенная) версия встроенной функции
count() иллюстрирует это: Вспомните, что есть две версии count(). С нулевыми аргументами count()
возвращает количество строк. С одним аргументом count() вернет
возвращает сколько раз аргументом был не-NULL. countStep() вызван однажды для каждой строки в совокупности. Как вы
видите, количество увеличено, если нет никаких аргументов или если один
аргумент не NULL. Ступенчатая функция для совокупности должна всегда начинаться с вызова
sqlite3_aggregate_context(),
чтобы получить постоянное состояние агрегатной функции. На первом вызове
функции step() совокупный контекст инициализируется к блоку памяти, который
имеет N байт в размере, где N это второй параметр
sqlite3_aggregate_context(), эта память обнулена.
На всех последующих обращениях к step()
возвращен тот же самый блок памяти. sqlite3_aggregate_context()
мог бы возвратить NULL в случае ошибки памяти, таким образом, агрегатные
функции должны быть готовы иметь дело с этим случаем. После того, как все строки обрабатываются, однократно вызывается
countFinalize(). Это вычисляет конечный результат и вызывает один из
sqlite3_result(), чтобы установить
конечный результат. Совокупный контекст будет освобожден автоматически
SQLite, хотя xFinalize() должен очистить любую структуру, связанную с
совокупным контекстом. Если xStep() вызовут один или несколько раз, то SQLite
гарантирует, что метод xFinal() вызовут, даже если запрос прервется. Функции окна
используют те же самые xStep() и xFinal(), которые используют агрегатные
функции плюс две других: xValue и xInverse. См.
здесь подробности. Есть десятки реализаций функции SQL, рассеянных всюду по исходному коду
SQLite, которые можно использовать в качестве примеров приложений. Встроенные
функции SQL используют тот же самый интерфейс, как определенные применением
функции SQL, таким образом, встроенные функции также могут использоваться в
качестве примеров. Поиск "sqlite3_context" в исходном коде SQLite поможет.
Определенные применением функции SQL могут стать уязвимостями
системы обеспечения безопасности, если не сделаны тщательно.
Предположим, например, применение определяет новую
SQL-функцию "system(X)", которая управляется ее аргументом X как командой и
возвращает код целого числа в качестве результата.
Возможно, внедрение похоже на это: Это функция с сильными побочными эффектами. Большинство программистов было
бы естественно осторожно в использовании такой штуки, но вероятно не будет
видеть вреда в простом наличии. Но есть большой риск в простом определении
такой функции, даже если само приложение никогда не использует ее! Предположим, что приложение обычно делает запрос к таблице TAB1, когда это
запускается. Если нападавший может получить доступ к файлу базы данных и
изменить схему так: то когда приложение пытается открыть базу данных, зарегистрировать функцию
system(), затем управлять невинным запросом к таблице "tab1",
оно вместо этого удаляет все файлы в своем рабочем каталоге. Чтобы предотвратить этот вид вреда, приложения, которые создают их
собственные функции SQL, должны использовать одну или больше
следующих мер безопасности: Вызывать sqlite3_db_config(db,
SQLITE_DBCONFIG_TRUSTED_SCHEMA,0,0) на каждом
соединении с базой данных
как только это открыто. Это препятствует тому, чтобы определенные
применением функции использовались в местах, где нападавший мог бы быть в
состоянии вызвать их, изменяя схему базы данных: Это урегулирование требует, чтобы определенными применением функциями
управлял только непосредственно SQL верхнего уровня,
вызванный от самого применения, а не в результате выполнения некоторого
другого невинно выглядящего запроса. Используйте PRAGMA
trusted_schema=OFF, чтобы отключить схему, которой доверяют.
Это имеет тот же самый эффект, как предыдущий совет, но не требует
использования C-кода и следовательно может быть выполнено в программах,
написанных на другом языке программирования, у которого нет
доступа к SQLite C API. Соберите SQLite с использованием опции времени компиляции
-DSQLITE_TRUSTED_SCHEMA=0.
Это заставляет SQLite не доверять определенным применением функциям
в схеме по умолчанию. Если у определенных применением функций SQL есть потенциально опасные
побочные эффекты, или если они могли бы потенциально пропустить уязвимую
информацию нападавшему, если неправильно используются, то помечайте те
функции, используя опцию
SQLITE_DIRECTONLY
в параметре "enc". Это означает, что функцией никогда нельзя управлять из
кода схемы, даже если идет выбор доверяемой схемы. Никогда не помечайте определенную применением функцию SQL
SQLITE_INNOCUOUS,
если вы действительно не должны это сделать, вы не проверили внедрение
полностью и уверены, что это не может причинить вреда,
даже если это подпадает под контроль нападавшего.
Choose any three.
1. Резюме
2.
Определение новых функций SQL
2.1. Общие параметры
2.2. Многократные вызовы sqlite3_create_function()
2.3. Отзывы
2.3.1.
Отзыв скалярной функции
static void noopfunc(sqlite3_context *context, int argc, sqlite3_value **argv)
{
assert(argc==1);
sqlite3_result_value(context, argv[0]);
}
2.3.2.
Отзывы агрегатной функции
typedef struct CountCtx CountCtx;
struct CountCtx
{
i64 n;
};
static void countStep(sqlite3_context *context, int argc,
sqlite3_value **argv)
{
CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
if ((argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0])) && p)
{
p->n++;
}
}
static void countFinalize(sqlite3_context *context)
{
CountCtx *p;
p = sqlite3_aggregate_context(context, 0);
sqlite3_result_int64(context, p ? p->n : 0);
}
2.3.3.
Отзывы функции окна
2.3.4. Примеры
3. О безопасности
static void systemFunc(sqlite3_context *context, int argc,
sqlite3_value **argv)
{
const char *zCmd = (const char*)sqlite3_value_text(argv[0]);
if (zCmd!=0)
{
int rc = system(zCmd);
sqlite3_result_int(context, rc);
}
}
ALTER TABLE tab1 RENAME TO tab1_real;
CREATE VIEW tab1 AS SELECT * FROM tab1 WHERE system('rm -rf *') IS NOT NULL;