Gestire la sicurezza del trigger

Si applica a: SQL Server database SQL di Azure Istanza gestita di SQL di Azure

Per impostazione predefinita, i trigger DML e DDL vengono eseguiti nel contesto dell'utente che li chiama. Il chiamante di un trigger è l'utente che esegue l'istruzione che causa l'esecuzione del trigger. Se ad esempio l'utente Mary esegue un'istruzione DELETE che causa l'esecuzione del trigger DML DML_trigMary , il codice all'interno di DML_trigMary viene eseguito nel contesto dei privilegi utente relativi a Mary. Il funzionamento predefinito può essere sfruttato dagli utenti che desiderano introdurre malware nel database o nell'istanza del server. Ad esempio, il trigger DDL seguente viene creato dall'utente 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

Il trigger indica che non appena un utente autorizzato a eseguire un'istruzione GRANT CONTROL SERVER, ad esempio un membro del ruolo predefinito del server sysadmin, esegue un'istruzione ALTER TABLE, all'utente JohnDoe viene concessa l'autorizzazione CONTROL SERVER. In altre parole, anche se JohnDoe non può concedere CONTROL SERVER l'autorizzazione a se stesso, ha abilitato il codice del trigger che gli concede tale autorizzazione per l'esecuzione con privilegi aumentati. I trigger DML e DDL sono esposti a questo tipo di minaccia per la sicurezza.

Procedure consigliate per la sicurezza dei trigger

Per impedire l'esecuzione del codice del trigger con privilegi alzati di livello, è possibile adottare le misure seguenti:

  • Individuare i trigger DML e DDL esistenti nel database e nell'istanza del server eseguendo query sulle viste del catalogo sys.triggers e sys.server_triggers . La query seguente restituisce tutti i trigger DML e DDL a livello di database nel database corrente e tutti i trigger DDL a livello di server nell'istanza del server:

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

    Nota

    Per il database SQL di Azure è disponibile solo sys.triggers a meno che non si usi l'istanza gestita di SQL di Azure.

  • Individuare i trigger DML e DDL esistenti nel database eseguendo query sulla vista del catalogo sys.triggers. La query seguente restituisce tutti i trigger DML e DDL a livello di database nel database corrente:

    SELECT type, name, parent_class_desc FROM sys.triggers;
    
  • Per disabilitare i trigger che possono compromettere l'integrità del database o del server se vengono eseguiti con privilegi alzati di livello, usare DISABLE TRIGGER . L'istruzione seguente disabilita tutti i trigger DDL a livello di database nel database corrente:

    DISABLE TRIGGER ALL ON DATABASE;
    

    L'istruzione seguente disabilita tutti i trigger DDL a livello di server nell'istanza del server:

    DISABLE TRIGGER ALL ON ALL SERVER;
    

    L'istruzione seguente disabilita tutti i trigger DML nel database corrente:

    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;