트리거 보안 관리

적용 대상:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

기본적으로 두 DML 및 DDL 트리거는 트리거를 호출하는 사용자의 컨텍스트에서 모두 실행됩니다. 트리거 호출자는 트리거를 실행시키는 문을 실행하는 사용자입니다. 예를 들어 Mary 라는 사용자가 DML 트리거 DML_trigMary 를 실행시키는 DELETE 문을 실행하면 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

이 트리거의 의미는 sysadmin 고정 서버 역할의 멤버와 같이 문을 실행할 GRANT CONTROL SERVER 수 있는 권한이 있는 사용자가 문을 실행하는 ALTER TABLE 즉시 JohnDoe에 사용 권한이 부여된다는 CONTROL SERVER 것입니다. 즉, JohnDoe 는 자신에게 권한을 부여 CONTROL SERVER 할 수 없지만 에스컬레이션된 권한으로 실행할 수 있는 권한을 부여하는 트리거 코드를 사용하도록 설정했습니다. DML 및 DDL 트리거는 모두 이러한 종류의 보안 위협에 열려 있습니다.

보안 모범 사례 트리거

트리거 코드가 에스컬레이션된 권한으로 실행되지 않도록 하려면 다음 조치를 취할 수 있습니다.

  • sys.triggers 및 sys.server_triggers 카탈로그 뷰를 쿼리하여 데이터베이스 및 서버 인스턴스에 있는 DML 및 DDL 트리거에 유의하세요. 다음 쿼리는 현재 데이터베이스의 모든 DML 및 데이터베이스 수준 DDL 트리거와 서버 인스턴스의 모든 서버 수준 DDL 트리거를 반환합니다.

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

참고 항목

Azure SQL Managed Instance를 사용하지 않는 한 Sys.triggersAzure SQL Database에 사용할 수 있습니다.

  • sys.triggers 카탈로그 뷰를 쿼리하여 데이터베이스에 있는 DML 및 DDL 트리거를 확인합니다. 다음 쿼리는 현재 데이터베이스의 모든 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;
    

참고 항목

CREATE TRIGGER(Transact-SQL)
DML 트리거
DDL 트리거
LOGON 트리거