Gerenciar a segurança do gatilho

Aplica-se a: SQL Server Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure

Por padrão, os gatilhos DML e DDL executam sob o contexto do usuário que aciona o gatilho. O chamador do gatilho é o usuário que executa a instrução que faz com que o gatilho execute. Por exemplo, se o usuário Marina executar uma instrução DELETE que faz com que o gatilho DML DML_trigMarina seja executado, o código dentro do DML_trigMarina executará no contexto dos privilégios do usuário para Marina. Esse comportamento padrão pode ser explorado pelos usuários que desejam apresentar um código mal-intencionado no banco de dados ou na instância do servidor. Por exemplo, o seguinte gatilho DDL é criado pelo usuário 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

O que esse gatilho significa é que assim que um usuário tiver a permissão para executar uma instrução GRANT CONTROL SERVER, como um membro da função de servidor fixa sysadmin, ele executará uma instrução ALTER TABLE, JohnDoe receberá a permissão CONTROL SERVER. Em outras palavras, embora JohnDoe não possa conceder a permissão CONTROL SERVER para si mesmo, ele habilitou o código de gatilho para ser executado com privilégios escalados, o que concede essa permissão. Os gatilhos DML e DDL estão abertos para este tipo de ameaça à segurança.

Melhores práticas para a segurança do gatilho

Você pode tomar as medidas a seguir para impedir que o código do gatilho execute sob privilégios escalados:

  • Lembre-se dos gatilhos DML e DDL que existem no banco de dados e na instância do servidor consultando as exibições de catálogo sys.triggers e sys.server_triggers . A consulta a seguir retorna todos os gatilhos DML e DDL no nível de banco de dados no banco de dados atual e todos os gatilhos DDL no nível de servidor na instância do servidor:

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

    Observação

    Somente o sys.triggers está disponível para o Banco de Dados SQL do Azure, a menos que você esteja usando a Instância Gerenciada de SQL do Azure.

  • Lembre-se dos gatilhos DML e DDL que existem no banco de dados ao consultar a exibição de catálogo sys.triggers. A consulta a seguir retorna todos os gatilhos DML e DDL no nível do banco de dados para o banco de dados atual:

    SELECT type, name, parent_class_desc FROM sys.triggers;
    
  • Use DISABLE TRIGGER para desabilitar os gatilhos que podem prejudicar a integridade do banco de dados ou do servidor caso sejam executados sob privilégios escalonados. A instrução a seguir desabilita todos os gatilhos DDL no nível do banco de dados no banco de dados atual:

    DISABLE TRIGGER ALL ON DATABASE;
    

    Essa instrução desabilita todos os gatilhos DDL no nível de servidor na instância do servidor:

    DISABLE TRIGGER ALL ON ALL SERVER;
    

    Essa instrução desabilita todos os gatilhos DML no banco de dados atual:

    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;