web-dev-qa-db-ja.com

SQL Serverを使用してデータを削除したユーザーを見つける方法

私の上司は昨日、顧客から、SQL Serverデータベースのデータを削除したユーザーを確認する方法について質問を受けました(重要な場合はExpress Editionです)。

これはトランザクションログから見つけることができると思いました(切り捨てられていなかった場合)-これは正しいですか?もしそうなら、実際にどのようにしてこの情報を見つけ出すのですか?

29
Matt Wilko

私はExpressでfn_dblogを試していませんが、それが利用可能な場合は、次のようにして削除操作を実行できます。

SELECT 
    * 
FROM 
    fn_dblog(NULL, NULL) 
WHERE 
    Operation = 'LOP_DELETE_ROWS'

関心のあるトランザクションのトランザクションIDを取得し、トランザクションを開始したSIDを特定します。

SELECT
    [Transaction SID]
FROM
    fn_dblog(NULL, NULL)
WHERE
    [Transaction ID] = @TranID
AND
    [Operation] = 'LOP_BEGIN_XACT'

次に、SIDからユーザーを識別します。

SELECT
    *
FROM 
    sysusers
WHERE
    [sid] = @SID

編集:これらすべてをまとめて、指定したテーブルの削除を見つけます。

DECLARE @TableName sysname
SET @TableName = 'dbo.Table_1'

SELECT
    u.[name] AS UserName
    , l.[Begin Time] AS TransactionStartTime
FROM
    fn_dblog(NULL, NULL) l
INNER JOIN
    (
    SELECT
        [Transaction ID]
    FROM 
        fn_dblog(NULL, NULL) 
    WHERE
        AllocUnitName LIKE @TableName + '%'
    AND
        Operation = 'LOP_DELETE_ROWS'
    ) deletes
ON  deletes.[Transaction ID] = l.[Transaction ID]
INNER JOIN
    sysusers u
ON  u.[sid] = l.[Transaction SID]
35

データベースが完全復旧モードの場合、またはトランザクションログのバックアップがある場合は、サードパーティのログリーダーを使用してこれらを読み取ってみることができます。

ApexSQL Log (プレミアムだが無料トライアルあり)または SQL Log Rescue (無料だがSQL 2000のみ)を試すことができる。

3
Tony Melanik

sQL Serverデータベースで一部のデータを削除したユーザーを見つける方法

これは回答されていますが、SQL Serverではデフォルトのトレースが有効になっており、オブジェクトをドロップ/変更したユーザーを見つけるために使用できることを追加したいと考えています。

オブジェクトイベント

オブジェクトイベントには、オブジェクト変更、オブジェクト作成、オブジェクト削除が含まれます。

注:SQL Serverにはデフォルトで5つのトレースファイルがあり、それぞれ20 MBあります。これを変更するためのサポートされている既知の方法はありません。システムがビジーな場合、トレースファイルのロールオーバーが非常に速く(数時間以内であっても)、一部の変更をキャッチできない可能性があります。

優れた例を見つけることができます: SQL Serverの既定のトレース-パフォーマンスとセキュリティ監査の力

3
Kin Shah

この手順を実行してログバックアップファイルにクエリを実行し、テーブルの列の特定の値がまだ/最後に存在していたログバックアップファイルを見つけることができます。

ユーザーを見つけるには、どのログバックアップで値が最後に存在したかを見つけた後、そのログバックアップまでデータベースを復元し、 Mark Storey-Smith の回答に従います。

いくつかの前提条件

  • どの列からどの値が削除されたかを知る
  • 完全復旧モデルの下にあり、ログのバックアップを取っている
  • ola Hallengrenのソリューションを使用する場合など、ログバックアップに日付または識別子がある

免責事項

このソリューションは防水性には程遠いため、さらに多くの作業が必要になります。

大規模な環境、またはいくつかの小規模なテスト以外の環境ではテストされていません。現在の実行はSQL Server 2017でした。

以下を使用できます 手順 from Muhammad Imranlog backupsライブデータベースのログの内容の代わりに。

この方法では、技術的には復元を行わず、代わりにログの内容を一時テーブルにダンプします。それはおそらく遅いでしょう、そしてバグと問題に非常にオープンです。しかし、理論的にはそれは機能します。

ストアドプロシージャは、文書化されていないfn_dump_dblog関数を使用してログファイルを読み取ります。


テスト環境

このデータベースでは、いくつかの行を挿入し、2つのログバックアップを取り、3番目のログバックアップではすべての行を削除します。

CREATE DATABASE WrongDeletesDatabase
GO
USE WrongDeletesDatabase
GO
BACKUP DATABASE WrongDeletesDatabase TO DISK ='c:\temp\Full.bak'

ALTER DATABASE WrongDeletesDatabase SET RECOVERY FULL
GO

CREATE TABLE dbo.WrongDeletes(ID INT, val varchar(255))

INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2.trn'
GO
DELETE FROM dbo.WrongDeletes
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4.trn'
GO

手順

ストアドプロシージャ here を見つけてダウンロードできます。

文字数制限よりも大きいため、ここに追加することはできません。この答えは、それよりも明確ではなくなります。

これとは別に、プロシージャを実行できるはずです。

プロシージャの実行

この例では、すべてのログファイル(4)をストアドプロシージャに追加し、value1を探すプロシージャを実行しています。

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes', 
                                    @SearchString = 'value1', 
                                    @SearchColumn = 'val',
                                    @LogBackupFolder ='C:\temp\Logs\'

これは私を取得します:

ID  val LogFileName
1   value1  c:\temp\Logs\log3.trn
1   value1  c:\temp\Logs\log1.trn

value1で最後に操作が行われた日時を確認できる場所で、log3.trnで削除します。

さらにいくつかのテストデータ、異なる列を持つテーブルを追加

CREATE TABLE dbo.WrongDeletes2(Wow varchar(255), Anotherval varchar(255),Val3 int)

INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (1,'value1')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('b','value1',1)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log1_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (2,'value2')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('c','value2',2)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log2_1.trn'
GO
DELETE FROM dbo.WrongDeletes
DELETE FROM dbo.WrongDeletes2
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log3_1.trn'
GO
INSERT INTO dbo.WrongDeletes(ID,val)
VALUES (3,'value3')
INSERT INTO dbo.WrongDeletes2(wOw,Anotherval,Val3)
VALUES ('d','value3',3)
GO
BACKUP LOG WrongDeletesDatabase TO DISK = 'c:\temp\Logs\log4_1.trn'
GO

ログファイル名の変更とプロシージャの再実行

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes', 
                                    @SearchString = 'value1', 
                                    @SearchColumn = 'val',
                                    @LogBackupFolder ='C:\temp\Logs\'

結果

ID  val LogFileName
1   value1  c:\temp\Logs\log1_1.trn
1   value1  c:\temp\Logs\log3_1.trn
1   value1  c:\temp\Logs\log3_1.trn

_2val3列で整数(dbo.WrongDeletes2)を検索する新しい実行

EXEC dbo.Recover_Deleted_Data_Proc  @Database_Name= 'WrongDeletesDatabase',
                                    @SchemaName_n_TableName= 'dbo.WrongDeletes2', 
                                    @SearchString = '2', 
                                    @SearchColumn = 'Val3',
                                    @LogBackupFolder ='C:\temp\Logs\'

結果

Anotherval  Val3    Wow LogFileName
value2  2   c   c:\temp\Logs\log2.trn
value2  2   c   c:\temp\Logs\log3.trn

Applying Mark Storey-Smith の回答

3番目のログファイルで発生したことがわかったので、その時点まで復元してみましょう。

USE master
GO
ALTER DATABASE WrongDeletesDatabase SET OFFLINE WITH ROLLBACK IMMEDIATE
GO
ALTER DATABASE WrongDeletesDatabase SET ONLINE 
GO
RESTORE DATABASE WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\Full.bak' WITH NORECOVERY,REPLACE
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log1.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log2.trn' WITH NORECOVERY
RESTORE LOG WrongDeletesDatabase FROM DISK = 'c:\temp\Logs\log3.trn' WITH RECOVERY
GO
USE WrongDeletesDatabase
GO

回答の最後のクエリを実行しています

SELECT
    u.[name] AS UserName
    , l.[Begin Time] AS TransactionStartTime
FROM
    fn_dblog(NULL, NULL) l
INNER JOIN
    (
    SELECT
        [Transaction ID]
    FROM 
        fn_dblog(NULL, NULL) 
    WHERE
        AllocUnitName LIKE @TableName + '%'
    AND
        Operation = 'LOP_DELETE_ROWS'
    ) deletes
ON  deletes.[Transaction ID] = l.[Transaction ID]
INNER JOIN
    sysusers u
ON  u.[sid] = l.[Transaction SID]

結果(sysadmin)

UserName    TransactionStartTime
dbo 2019/08/09 17:14:10:450
dbo 2019/08/09 17:14:10:450
1
Randi Vertongen