Управление безопасностью триггера

Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure

Как триггеры DML, так и триггеры DDL по умолчанию выполняются в контексте того пользователя, который вызывает триггер. Это пользователь, который выполняет инструкцию, вызывающую запуск триггера. Например, если пользователь Mary выполняет инструкцию DELETE, которая запускает триггер DML DML_trigMary , то код внутри DML_trigMary выполняется в контексте прав доступа пользователя Mary. Этим поведением по умолчанию могут воспользоваться те пользователи, которые хотят внести небезопасный код в экземпляр базы данных или сервера. Например, следующий триггер DDL создан пользователем JohnDoe:

CREATE TRIGGER DDL_trigJohnDoe
ON DATABASE
FOR ALTER_TABLE
AS
SET NOCOUNT ON;

BEGIN TRY
  EXEC(N'
    USE [master];
    GRANT CONTROL SERVER TO [JohnDoe];
');
END TRY
BEGIN CATCH
  DECLARE @DoNothing INT;
END CATCH;
GO

В этом триггере подразумевается, что как только пользователь с разрешением на выполнение инструкции GRANT CONTROL SERVER, например член предопределенной роли сервера sysadmin, выполнит инструкцию ALTER TABLE, пользователь JohnDoe получит разрешение CONTROL SERVER. Иными словами, хотя JohnDoe не может предоставить CONTROL SERVER себе разрешение, они включили код триггера, предоставляющий им это разрешение на выполнение при повышенных привилегиях. Эта уязвимость относится как к триггерам DML, так и к триггерам DDL.

Рекомендации по обеспечению безопасности триггеров

Чтобы предотвратить выполнение кода триггера с повышенными правами доступа, примите следующие меры.

  • Проверьте базу данных и экземпляр сервера на наличие триггеров DDL и DDL. Для этого выполните соответствующие запросы к представлениям каталогов sys.triggers и sys.server_triggers . Следующий запрос возвращает все триггеры DML и DDL уровня базы данных в текущей базе данных, а также все триггеры DDL уровня сервера на экземпляре сервера.

    SELECT type, name, parent_class_desc FROM sys.triggers
    UNION ALL
    SELECT type, name, parent_class_desc FROM sys.server_triggers;
    

    Примечание.

    Только sys.triggers доступно для База данных SQL Azure, если вы не используете Управляемый экземпляр SQL Azure.

  • Проверьте базу данных на наличие триггеров DDL и DDL. Для этого выполните соответствующие запросы к представлению каталога sys.triggers. Следующий запрос возвращает все триггеры DML и триггеры DDL уровня базы данных в текущей базе данных:

    SELECT type, name, parent_class_desc FROM sys.triggers;
    
  • С помощью инструкции DISABLE TRIGGER запретите триггеры, которые могут нарушить целостность базы данных или сервера при выполнении с повышенными правами доступа. Следующая инструкция отключает все триггеры DDL уровня базы данных в текущей базе данных:

    DISABLE TRIGGER ALL ON DATABASE;
    

    Эта инструкция отключает все триггеры DDL уровня сервера на экземпляре сервера:

    DISABLE TRIGGER ALL ON ALL SERVER;
    

    Эта инструкция отключает все триггеры DML в текущей базе данных:

    DECLARE @schema_name sysname, @trigger_name sysname, @object_name sysname;
    DECLARE @sql nvarchar(max);
    DECLARE trig_cur CURSOR FORWARD_ONLY READ_ONLY FOR
        SELECT SCHEMA_NAME(schema_id) AS schema_name,
            name AS trigger_name,
            OBJECT_NAME(parent_object_id) AS object_name
        FROM sys.objects WHERE type IN ('TR', 'TA');
    
    OPEN trig_cur;
    FETCH NEXT FROM trig_cur INTO @schema_name, @trigger_name, @object_name;
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SELECT @sql = N'DISABLE TRIGGER ' + QUOTENAME(@schema_name) + N'.'
            + QUOTENAME(@trigger_name)
            + N' ON ' + QUOTENAME(@schema_name) + N'.'
            + QUOTENAME(@object_name) + N'; ';
        EXEC (@sql);
        FETCH NEXT FROM trig_cur INTO @schema_name, @trigger_name, @object_name;
    END;
    GO
    
    -- Verify triggers are disabled. Should return an empty result set.
    SELECT * FROM sys.triggers WHERE is_disabled = 0;
    GO
    
    CLOSE trig_cur;
    DEALLOCATE trig_cur;