27.6 Управление доступом к хранимым объектам
Хранимые программы (процедуры, функции, триггеры и события) и представления определяются до использования и, при обращении к ним, выполняют действия в контексте безопасности, определяющем их привилегии. Привилегии, применимые к выполнению хранимого объекта, контролируются его атрибутом DEFINER и характеристикой SQL SECURITY.
Атрибут DEFINER
Определение хранимого объекта может включать атрибут DEFINER, который указывает на учетную запись MySQL. Если определение опускает атрибут DEFINER, по умолчанию определяет объект пользователь, который его создал.
Следующие правила определяют, какие учетные записи вы можете указать в качестве атрибута DEFINER для хранимого объекта:
Если у вас есть привилегия
SET_ANY_DEFINER, вы можете указать любую учетную запись в качестве атрибутаDEFINER. Если учетная запись не существует, генерируется предупреждение. Кроме того, чтобы установить атрибут хранимого объектаDEFINERна учетную запись, имеющую привилегиюSYSTEM_USER, вам необходимо иметь привилегиюSYSTEM_USER.В противном случае единственная разрешенная учетная запись — ваша собственная, указанная либо явно, либо как
CURRENT_USERилиCURRENT_USER(). Вы не можете установить для определённого объекта другой пользователь.
Создание хранимого объекта с несуществующей учетной записью DEFINER создает объект-сироту, что может иметь негативные последствия; см. Хранимые объекты-сироты.
Характеристика SQL SECURITY
Для хранимых процедур (процедур и функций) и представлений определение объекта может включать характеристику SQL SECURITY со значением DEFINER или INVOKER, чтобы указать, выполняет ли объект действия в контексте пользователя-определяющего (definer) или вызывающего (invoker). Если определение опускает характеристику SQL SECURITY, по умолчанию используется контекст пользователя-определяющего.
Триггеры и события не имеют характеристики SQL SECURITY и всегда выполняются в контексте пользователя-определяющего. Сервер вызывает эти объекты автоматически по мере необходимости, поэтому нет вызывающего пользователя.
Контексты безопасности пользователя-определяющего (definer) и вызывающего (invoker) различаются следующим образом:
Хранимый объект, выполняемый в контексте безопасности пользователя-определяющего, выполняется с привилегиями учетной записи, указанной в его атрибуте
DEFINER. Эти привилегии могут полностью отличаться от привилегий вызывающего пользователя. Вызывающий пользователь должен иметь соответствующие привилегии для обращения к объекту (например,EXECUTEдля вызова хранимой процедуры илиSELECTдля выборки из представления), но во время выполнения объекта привилегии вызывающего пользователя игнорируются, и учитываются только привилегии учетной записиDEFINER. Если учетная записьDEFINERимеет ограниченный набор привилегий, объект также ограничен в выполняемых операциях. Если учетная записьDEFINERимеет высокие привилегии (например, административная учетная запись), объект может выполнять мощные операции независимо от того, кто его вызывает.Хранимая процедура или представление, выполняемая в контексте безопасности вызывающего пользователя, может выполнять только те операции, для которых вызывающий пользователь имеет привилегии. Атрибут
DEFINERне оказывает влияния на выполнение объекта.
Примеры
Рассмотрим следующую хранимую процедуру, объявленную с SQL SECURITY DEFINER, чтобы выполняться в контексте безопасности пользователя-определяющего:
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
UPDATE t1 SET counter = counter + 1;
END;
Любой пользователь, имеющий привилегию EXECUTE для p1, может вызвать её с помощью оператора CALL. Однако, когда p1 выполняется, она делает это в контексте безопасности пользователя-определяющего и, таким образом, выполняется с привилегиями учетной записи 'admin'@'localhost', указанной в качестве ее атрибута DEFINER. Эта учетная запись должна иметь привилегию EXECUTE для p1, а также привилегию UPDATE для таблицы t1, указанной в теле объекта. В противном случае процедура завершится с ошибкой.
Теперь рассмотрим эту хранимую процедуру, идентичную p1, за исключением того, что ее характеристика SQL
SECURITY имеет значение INVOKER:
CREATE DEFINER = 'admin'@'localhost' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
UPDATE t1 SET counter = counter + 1;
END;
В отличие от p1, p2 выполняется в контексте безопасности вызывающего пользователя и, таким образом, с привилегиями вызывающего пользователя независимо от значения атрибута DEFINER. p2 завершится с ошибкой, если у вызывающего пользователя отсутствуют привилегии EXECUTE для p2 или UPDATE для таблицы t1.
Сироты хранимых объектов
Хранимый объект-сирота — это объект, для которого его атрибут DEFINER указывает на несуществующую учётную запись:
Хранимый объект-сирота может быть создан путём указания несуществующей
DEFINERучётной записи во время создания объекта.Существующий хранимый объект может стать сиротой в результате выполнения инструкции
DROP USER, которая удаляет учётную запись объектаDEFINER, или инструкцииRENAME USER, которая переименовывает учётную запись объектаDEFINER.
Хранимый объект-сирота может быть проблематичен в следующих отношениях:
-
Поскольку учётная запись
DEFINERне существует, объект может не работать должным образом, если он выполняется в контексте безопасности определяющего пользователя:Для хранимой процедуры ошибка возникает во время выполнения процедуры, если значение
SQL SECURITYравноDEFINER, но определяющая учётная запись не существует.Для триггера нежелательно, чтобы активация триггера происходила до фактического существования учётной записи. В противном случае поведение с точки зрения проверки привилегий является неопределённым.
Для события ошибка возникает во время выполнения события, если учётная запись не существует.
Для представления ошибка возникает при обращении к представлению, если значение
SQL SECURITYравноDEFINER, но определяющая учётная запись не существует.
Объект может представлять собой угрозу безопасности, если несуществующая учётная запись
DEFINERвпоследствии будет создана с целью, не связанной с объектом. В этом случае учётная запись “усыновляет” объект и, имея соответствующие привилегии, может его выполнить, даже если это не предполагалось.
Сервер выполняет следующие проверки безопасности управления учётными записями, предназначенные для предотвращения операций, которые (возможно, непреднамеренно) приводят к тому, что хранимые объекты становятся сиротами, или к тому, что хранимые объекты, которые в настоящее время являются сиротами, усыновляются:
DROP USERзавершается ошибкой, если любая удаляемая учётная запись указана в качестве атрибутаDEFINERдля любого хранимого объекта. (То есть, инструкция завершается ошибкой, если удаление учётной записи приведёт к тому, что хранимый объект станет сиротой.)RENAME USERзавершается ошибкой, если любая переименовываемая учётная запись указана в качестве атрибутаDEFINERдля любого хранимого объекта. (То есть, инструкция завершается ошибкой, если переименование учётной записи приведёт к тому, что хранимый объект станет сиротой.)CREATE USERзавершается ошибкой, если любая создаваемая учётная запись указана в качестве атрибутаDEFINERдля любого хранимого объекта. (То есть, инструкция завершается ошибкой, если создание учётной записи приведёт к тому, что учётная запись усыновит текущий хранимый объект-сироту.)
В некоторых ситуациях может потребоваться преднамеренно выполнить эти инструкции управления учётными записями, даже если они иначе завершатся ошибкой. Для этого, если у пользователя есть привилегия ALLOW_NONEXISTENT_DEFINER, эта привилегия переопределяет проверки безопасности объектов-сирот, и инструкции завершатся предупреждением, а не ошибкой.
Чтобы получить информацию об учётных записях, используемых в качестве определяющих пользователей хранимых объектов в установке MySQL, выполните запрос к таблице INFORMATION_SCHEMA.
Этот запрос определяет, какие таблицы INFORMATION_SCHEMA описывают объекты, имеющие атрибут DEFINER:
mysql> SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME = 'DEFINER';
+--------------------+------------+
| TABLE_SCHEMA | TABLE_NAME |
+--------------------+------------+
| information_schema | EVENTS |
| information_schema | ROUTINES |
| information_schema | TRIGGERS |
| information_schema | VIEWS |
+--------------------+------------+
Результат показывает, какие таблицы нужно запросить, чтобы узнать, какие значения хранимых объектов DEFINER существуют и какие объекты имеют определённое значение DEFINER:
-
Чтобы определить, какие значения
DEFINERсуществуют в каждой таблице, используйте эти запросы:SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.EVENTS; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.ROUTINES; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS; SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.VIEWS;
Результаты запроса важны для любой учётной записи, отображаемой следующим образом:
Если учётная запись существует, её удаление или переименование приводит к тому, что хранимые объекты становятся сиротами. Если вы планируете удалить или переименовать учётную запись, сначала рассмотрите возможность удаления связанных хранимых объектов или переопределения их с использованием другого определяющего пользователя.
Если учётная запись не существует, её создание приводит к тому, что она усыновляет текущие хранимые объекты-сироты. Если вы планируете создать учётную запись, рассмотрите вопрос о том, должны ли к ней быть связаны объекты-сироты. Если нет, переопределите их с использованием другого определяющего пользователя.
Чтобы переопределить объект с использованием другого определяющего пользователя, можно использовать
ALTER EVENTилиALTER VIEWдля непосредственного изменения учётной записиDEFINERсобытий и представлений. Для хранимых процедур и функций и триггеров необходимо удалить объект и создать его заново, чтобы назначить другую учётную записьDEFINER. -
Чтобы определить, какие объекты имеют заданную учётную запись
DEFINER, используйте эти запросы, заменив интересующую учётную запись на:user_name@host_nameSELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS WHERE DEFINER = '
user_name@host_name'; SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE FROM INFORMATION_SCHEMA.ROUTINES WHERE DEFINER = 'user_name@host_name'; SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS WHERE DEFINER = 'user_name@host_name'; SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS WHERE DEFINER = 'user_name@host_name';Для таблицы
ROUTINESзапрос включает столбецROUTINE_TYPE, чтобы строки вывода различали, является лиDEFINERхранимой процедурой или хранимой функцией.Если учётная запись, которую вы ищете, не существует, все объекты, отображённые этими запросами, являются объектами-сиротами.
Рекомендации по минимизации рисков
Для минимизации потенциальных рисков при создании и использовании хранимых объектов следуйте этим рекомендациям:
Не создавайте оторванные хранимые объекты; то есть, объекты, для которых атрибут
DEFINERуказывает на несуществующий аккаунт. Не допускайте, чтобы хранимые объекты становились оторванными, удаляя или переименовывая аккаунт, указанный атрибутомDEFINERлюбого существующего объекта.Для хранимой процедуры или представления, используйте
SQL SECURITY INVOKERв определении объекта, когда это возможно, чтобы он мог быть использован только пользователями с правами, соответствующими операциям, выполняемым объектом.Если вы создаете хранимые объекты контекста определённого пользователем при использовании аккаунта, обладающего правом
SET_ANY_DEFINER, укажите явный атрибутDEFINER, который назначает аккаунт, обладающий только необходимыми для выполняемых объектом операций правами. Указывайте высокопривилегированный аккаунтDEFINERтолько в том случае, если это абсолютно необходимо.Администраторы могут предотвратить создание пользователями хранимых объектов, которые указывают высокопривилегированные аккаунты
DEFINER, не предоставляя им правоSET_ANY_DEFINER.-
Объекты контекста определения должны быть написаны с учетом того, что они могут получать доступ к данным, для которых у вызывающего пользователя нет прав. В некоторых случаях вы можете предотвратить ссылки на эти объекты, не предоставляя неавторизованным пользователям определённых привилегий:
Однако, такого контроля не существует для триггеров и событий, так как они всегда выполняются в контексте определённого пользователя. Сервер вызывает эти объекты автоматически по мере необходимости, и пользователи не ссылаются на них напрямую:
Триггер активируется доступом к таблице, с которой он связан, даже обычными обращениями к таблице со стороны пользователей без специальных привилегий.
Событие выполняется сервером по расписанию.
В обоих случаях, если аккаунт
DEFINERимеет высокие привилегии, объект может выполнять конфиденциальные или опасные операции. Это остается справедливым, даже если права, необходимые для создания объекта, отозваны у учётной записи пользователя, который его создал. Администраторы должны быть особенно внимательны при предоставлении пользователям прав на создание объектов. По умолчанию, при выполнении процедуры с характеристикой
SQL SECURITY DEFINER, сервер MySQL не устанавливает активные роли для учётной записи MySQL, указанной в предложенииDEFINER, а только роли по умолчанию. Исключением является случай, когда переменная системыactivate_all_roles_on_loginвключена, в этом случае сервер MySQL устанавливает все роли, предоставленные пользователюDEFINER, включая обязательные роли. Следовательно, по умолчанию любые привилегии, предоставленные через роли, не проверяются при выполнении операторовCREATE PROCEDUREилиCREATE FUNCTION. Для хранимых программ, если выполнение должно происходить с ролями, отличными от по умолчанию, тело программы может выполнитьSET ROLEдля активации необходимых ролей. Это следует делать с осторожностью, так как привилегии, назначенные ролям, могут быть изменены.
© 2025 Oracle
Licensed under the GPLv2 License.