Gerenciando a segurança dos gatilhos

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 Mary executar uma instrução DELETE que faz com que o gatilho DMLDML_trigMary seja executado, o código dentro do DML_trigMary executará no contexto dos privilégios do usuário para Mary. 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 disparador DDL a seguir é criado pelo usuário JohnDoe:

CREATE TRIGGER DDL_trigJohnDoe

ON DATABASE

FOR ALTER_TABLE

AS

GRANT CONTROL SERVER TO JohnDoe ;

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 executa uma instrução ALTER TABLE, JohnDoe recebe permissão CONTROL SERVER. Em outras palavras, embora JohnDoe não possa conceder permissão CONTROL SERVER para ele mesmo, ele habilita o código do gatilho que lhe concede essa permissão para executar sob privilégios escalados. Os gatilhos DML e DDL estão abertos para este tipo de ameaça à segurança.

Práticas recomendadas para a segurança dos gatilhos

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 disparadores DDL no nível de servidor na instância do servidor:

    SELECT type, name, parent_class_desc FROM sys.triggers
    UNION
    SELECT type, name, parent_class_desc FROM sys.server_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 escalados. A instrução a seguir desabilita todos os disparadores DDL no nível do banco de dados no banco de dados atual:

    DISABLE TRIGGER ALL ON DATABASE
    

    Essa instrução desabilita todos os disparadores 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 = 'DISABLE TRIGGER ' + QUOTENAME(@schema_name) + '.'
            + QUOTENAME(@trigger_name) +
            ' ON ' + QUOTENAME(@schema_name) + '.' 
            + QUOTENAME(@object_name) + ' ; ' ;
        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;