MS-SQL 2008 R2のデータベースを使用していて、問題が発生しています。
基本的なセットアップは次のとおりです。dbo.Assesmentsとaudit.Assesmentsの2つの対象テーブルがあります。 dbo.Assesmentsは作業データテーブルであり、変更のログでaudit.Assesmentsを更新するためのデータ変更(挿入、更新、削除)のトリガーがあります。私の知る限り、これは何年にもわたって機能しています。
私たちのL2サポートには、WinAuthで取得するSupportRoleと呼ばれるロールがあり、そのロールには、ストアドプロシージャに対するいくつかの選択権と実行権があります。これらのストアドプロシージャの1つは、dbo.Assesmentsを更新します。ここで問題が発生します。更新が行われ、ストアドプロシージャが起動して、audit.Assesmentsに監査行が挿入されます。その後、「挿入の拒否、挿入に対する不十分な権限」、トランザクションロールなどがすぐに返されます。
これは私にとって不可解です。トリガーはストアドプロシージャのようなものだと思っていました。トリガーが作成された場合、トリガーは何をする権利も持っているのですが、これは2度考えさせられます。監査テーブル/スキーマのサポートロールに挿入権限を与えたくありません。私は何をすべきか?
トリガーは、デフォルトでは、トリガーを起動したプリンシパルのセキュリティコンテキストで実行されます。
この動作を変更するには、WITH EXECUTE AS OWNER
句を使用してトリガーを作成する必要があります。
以下は、それがどのように機能するかを示す例です。 WITH EXECUTE AS OWNER
を使用すると、テーブルを更新しているプリンシパルではなく、データベース所有者のセキュリティコンテキストでトリガーを実行できます。
まず、テストテーブルを作成します。
USE tempdb;
IF OBJECT_ID('dbo.t') IS NOT NULL
BEGIN
DROP TRIGGER t_trig;
DROP TABLE dbo.t;
END
GO
CREATE TABLE dbo.t
(
ID INT NOT NULL
, ID2 INT NULL
);
GO
これがEXECUTE AS OWNER
を含むトリガーコードです。
CREATE TRIGGER t_trig ON dbo.t
WITH EXECUTE AS OWNER
AFTER INSERT
AS
BEGIN
UPDATE dbo.t
SET ID2 = ID
WHERE EXISTS (SELECT 1 FROM inserted i WHERE i.ID = dbo.t.ID);
END
GO
ここで、低い特権でテストログインを作成し、EXECUTE AS OWNER
が本来必要としない機能への特権不足のプリンシパルアクセスを許可するという仮説をテストするために使用できます。
CREATE LOGIN tLogin WITH PASSWORD = 'QWERFsdf23454%';
CREATE USER tLogin FROM LOGIN tLogin WITH DEFAULT_SCHEMA = dbo;
dbo.T
に行を挿入する機能を提供しますが、UPDATE
ステートメントを実行できないようにします。
GRANT INSERT ON dbo.t TO tLogin;
DENY UPDATE ON dbo.t TO tLogin;
ここでテストを行います:
EXECUTE AS USER = 'tLogin';
/*
Output here shows we're running under the tLogin
security context
*/
SELECT SUSER_SNAME();
/*
This will fail, with insufficient privileges
since we've DENY'd the UPDATE privilege to tLogin.
*/
UPDATE dbo.t SET ID2 = ID;
/*
this will run the UPDATE since the trigger
has EXECUTE AS OWNER
*/
INSERT INTO dbo.t(ID) VALUES (1);
/*
This takes us out of the tLogin security context
*/
REVERT
ここで、dbo.T
の行にトリガーによって行われた変更があることがわかります。
SELECT *
FROM dbo.t;
そして、ここでは、低い特権のユーザーをクリーンアップします。
DROP USER tLogin;
DROP LOGIN tLogin;
上記を実行した場合の出力は次のとおりです。