Share via


トリガーのセキュリティの管理

既定では、DML トリガーも DDL トリガーも、トリガーを呼び出したユーザーのコンテキストで実行されます。 トリガーの呼び出し元は、トリガーが実行される原因となったステートメントを実行したユーザーです。 たとえば、ユーザー Mary が DELETE ステートメントを実行し、このために DML トリガー DML_trigMary が実行された場合、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 ステートメントを実行した直後に、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
    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;
    

関連項目

参照

CREATE TRIGGER (Transact-SQL)

概念

DML トリガー

DDL トリガー