it-swarm.it

Come scoprire chi ha eliminato alcuni dati SQL Server

Ieri il mio capo ha ricevuto una richiesta da un cliente che chiedeva come potevano scoprire chi aveva eliminato alcuni dati nel loro database di SQL Server (è l'edizione espressa se conta).

Ho pensato che questo potesse essere trovato nel registro delle transazioni (a condizione che non fosse stato troncato) - è corretto? E se sì, come si fa effettivamente a trovare queste informazioni?

29
Matt Wilko

Non ho provato fn_dblog su Express ma se è disponibile quanto segue ti darà operazioni di eliminazione:

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

Prendi l'ID transazione per le transazioni che ti interessano e identifica il SID che ha avviato la transazione con:

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

Quindi identificare l'utente dal SID:

SELECT
    *
FROM 
    sysusers
WHERE
    [sid] = @SID

Modifica: riunendo tutto per trovare le eliminazioni su una tabella specificata:

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

Se il database è in modalità di recupero completo o se si dispone di backup del registro delle transazioni, è possibile provare a leggerli utilizzando lettori di registro di terze parti.

Puoi provare ApexSQL Log (premium ma ha una prova gratuita) o SQL Log Rescue (gratuito ma solo sql 2000).

3
Tony Melanik

come hanno potuto scoprire chi ha eliminato alcuni dati nel loro database di SQL Server

Nonostante ciò abbia risposto, ha voluto aggiungere che SQL Server ha una traccia predefinita abilitata e può essere usata per scoprire chi ha lasciato/modificato gli oggetti.

Eventi oggetto

Gli eventi oggetto includono: Oggetto modificato, Oggetto creato ed Oggetto eliminato

nota: SQL Server per impostazione predefinita ha 5 file di traccia, 20 MB ciascuno e non è noto alcun metodo supportato per modificarlo. Se si dispone di un sistema occupato, i file di traccia potrebbero scorrere troppo velocemente (anche entro poche ore) e potrebbe non essere possibile rilevare alcune delle modifiche.

Un esempio eccellente può essere trovato: La traccia predefinita in SQL Server - la potenza del controllo delle prestazioni e della sicurezza

3
Kin Shah

È possibile provare questa procedura per interrogare i file di backup del registro e trovare in quali file di backup del registro un valore specifico di una colonna di una tabella era ancora/presente per ultimo.

Per trovare l'utente, dopo aver trovato nel backup del registro l'ultimo valore esistente, è possibile ripristinare un database fino al backup del registro e quindi seguire la risposta di Mark Storey-Smith .

Alcuni prerequisiti

  • sapere quali valori da quali colonne sono state eliminate
  • Sono sotto il modello di recupero completo e stanno eseguendo i backup del registro
  • hai date o identificatori nei tuoi backup di log, come quando usi la soluzione di Ola Hallengren

Esonero di responsabilità

Questa soluzione è tutt'altro che impermeabile e richiede molto più lavoro.

Non è stato testato su ambienti di grandi dimensioni, o su qualsiasi ambiente, a parte alcuni piccoli test. L'esecuzione corrente era su SQL Server 2017.

È possibile utilizzare di seguito procedura da Muhammad Imran che ho modificato per funzionare con il contenuto di backup del registro invece del contenuto del registro di un database live.

In questo modo tecnicamente non si eseguono ripristini, ma si scarica invece il contenuto del registro in una tabella temporanea. Probabilmente sarà ancora lento, ed è molto aperto a bug e problemi. Ma potrebbe funzionare, in teoria ™.

La procedura memorizzata utilizza la funzione fn_dump_dblog Non documentata per leggere i file di registro.


Ambiente di test

Considera questo database, in cui inseriamo alcune righe, eseguiamo 2 backup del log e sul terzo backup del log eliminiamo tutte le righe.

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

La procedura

È possibile trovare e scaricare la procedura memorizzata qui .

Non potrei aggiungerlo qui poiché è più grande del limite del personaggio e renderebbe questa risposta ancora meno chiara di quello che è.

A parte questo, dovresti essere in grado di eseguire la procedura.

Esecuzione della procedura

Un esempio di ciò, quando aggiungo tutti i miei file di registro (4) Alla procedura memorizzata ed eseguo la procedura cercando value1

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

Questo mi fa:

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

Dove possiamo trovare quando è avvenuta l'ultima operazione su value1, L'eliminazione in log3.trn.

Alcuni dati di test aggiuntivi, aggiunta di una tabella con colonne diverse

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

Modifica dei nomi dei file di registro ed esecuzione di nuovo della procedura

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

Risultato

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

Una nuova corsa, alla ricerca dell'intero (2) Nella colonna val3 Di dbo.WrongDeletes2

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

Risultato

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

Applicazione Mark Storey-Smith 's answer

Ora sappiamo che è successo nel terzo file di registro, ripristiniamo fino a quel punto:

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

Esecuzione dell'ultima query nella sua risposta

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]

Risultato per me (amministratore di sistema)

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