27.7 Управление доступом к хранимым объектам
Хранимые программы (процедуры, функции, триггеры и события) и представления определяются до использования и, при обращении к ним, выполняется в контексте безопасности, который определяет их привилегии. Привилегии, применимые к выполнению хранимого объекта, контролируются его 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, чтобы указать, выполняется ли объект в контексте определяющего пользователя или вызывающего пользователя. Если определение опускает характеристику SQL SECURITY, по умолчанию используется контекст определяющего пользователя.
Триггеры и события не имеют характеристики SQL SECURITY и всегда выполняются в контексте определяющего пользователя. Сервер вызывает эти объекты автоматически по мере необходимости, поэтому нет вызывающего пользователя.
Контексты безопасности определяющего и вызывающего пользователя различаются следующим образом:
Хранимый объект, выполняющийся в контексте безопасности определяющего пользователя, выполняется с привилегиями учётной записи, указанной в его атрибуте
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 Server не устанавливает активные роли для учётной записи MySQL, указанной в предложенииDEFINER, устанавливаются только роли по умолчанию. Исключением является случай, когда системная переменнаяactivate_all_roles_on_loginвключена, в этом случае MySQL Server устанавливает все роли, предоставленные пользователюDEFINER, включая обязательные роли. Следовательно, любые привилегии, предоставленные через роли, по умолчанию не проверяются при выполнении оператораCREATE PROCEDUREилиCREATE FUNCTION. Для хранимых программ, если необходимо выполнение с ролями, отличными от стандартных, тело программы может выполнитьSET ROLEдля активации требуемых ролей. Это следует делать с осторожностью, так как привилегии, назначенные ролям, могут быть изменены.
© 2025 Oracle
Licensed under the GPLv2 License.