Partage via


Gérer la sécurité des déclencheurs

S’applique à : SQL Server Azure SQL Database Azure SQL Managed Instance

Par défaut, les déclencheurs DML et DDL s'exécutent dans le contexte de l'utilisateur ayant appelé le déclencheur. L'appelant d'un déclencheur correspond à l'utilisateur exécutant l'instruction qui provoque l'activation du déclencheur. Par exemple, si l’utilisatrice Mary exécute une instruction DELETE provoquant l’activation d’un déclencheur DML intitulé DML_trigMary , le code inclus dans DML_trigMary s’exécute dans le contexte des autorisations utilisateur associées à Mary. Ce comportement par défaut peut malheureusement être exploité par des utilisateurs mal intentionnés voulant introduire du code dangereux dans une base de données ou une instance de serveur. Prenons pour exemple le déclencheur DDL suivant créé par l’utilisateur 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

Ce déclencheur signifie que dès qu’un utilisateur disposant de l’autorisation d’exécuter une instruction GRANT CONTROL SERVER, comme un membre du rôle serveur fixe sysadmin, exécute une instruction ALTER TABLE, JohnDoe se voit octroyer l’autorisation CONTROL SERVER. En d’autres termes, même si JohnDoe ne peut pas s’accorder lui-même l’autorisation CONTROL SERVER, il a activé le code du déclencheur qui lui accorde cette autorisation pour qu’il s’exécute sous des privilèges promus. Aussi bien les déclencheurs DML que les déclencheurs DDL permettent ce type de menace de sécurité.

Meilleures pratiques pour la sécurité liée aux déclencheurs

Nous vous proposons les mesures suivantes pour éviter que du code de déclencheur s'exécute sous des privilèges promus :

  • Prenez connaissance des déclencheurs DML et DDL existant dans la base de données et sur l’instance du serveur en interrogeant les vues de catalogue sys.triggers et sys.server_triggers . La requête suivante renvoie tous les déclencheurs DML de la base de données actuelle, tous les déclencheurs DDL au niveau de la base de données actuelle et tous les déclencheurs DDL de niveau serveur inclus dans l'instance du serveur :

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

    Remarque

    Seul sys.triggers est disponible pour la base de données Azure SQL, sauf si vous utilisez Azure SQL Managed Instance.

  • Prenez connaissance des déclencheurs DML et DDL existant dans la base de données en interrogeant la vue de catalogue sys.triggers. La requête suivante retourne tous les déclencheurs DDL de niveau base de données et DML dans la base de données actuelle :

    SELECT type, name, parent_class_desc FROM sys.triggers;
    
  • Utilisez DISABLE TRIGGER afin de désactiver les déclencheurs pouvant mettre en péril l’intégrité de la base de données ou du serveur si les déclencheurs s’exécutent sous des privilèges promus. L'instruction suivante désactive tous les déclencheurs DDL de niveau base de données dans la base de données actuelle :

    DISABLE TRIGGER ALL ON DATABASE;
    

    L'instruction suivante désactive tous les déclencheurs DDL de niveau serveur sur l'instance du serveur :

    DISABLE TRIGGER ALL ON ALL SERVER;
    

    Enfin, cette instruction désactive tous les déclencheurs DML de la base de données actuelle :

    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;