기본적으로 두 DML 및 DDL 트리거는 트리거를 호출하는 사용자의 컨텍스트에서 모두 실행됩니다. 트리거 호출자는 트리거를 실행시키는 문을 실행하는 사용자입니다. 예를 들어 Mary 라는 사용자가 DML 트리거 DML_trigMary 를 실행시키는 DELETE 문을 실행하면 DML_trigMary 내에 있는 코드는 Mary에 대한 사용자 권한 컨텍스트에서 실행됩니다. 이 기본 동작은 데이터베이스 또는 서버 인스턴스에 악성 코드를 도입하려는 사용자가 악용할 수 있습니다. 예를 들어 다음 DDL 트리거는 사용자가 JohnDoe만듭니다.
CREATE TRIGGER DDL_trigJohnDoe
ON DATABASE
FOR ALTER_TABLE
AS
GRANT CONTROL SERVER TO JohnDoe ;
GO
이 트리거의 의미는 sysadmin 고정 서버 역할의 멤버와 같이 GRANT CONTROL SERVER 문을 실행할 수 있는 권한이 있는 사용자가 ALTER TABLE 문을 실행하면 JohnDoeCONTROL 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 SELECT type, name, parent_class_desc FROM sys.server_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 = '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;