Encontre a identidade do cliente que dispara uma consulta no SQL Server sem usar gatilhos?

11

Atualmente, estou usando o Change Data Capture (CDC) para rastrear alterações de dados e desejo rastrear o nome do host e o endereço IP do cliente que enviou a consulta que fez as alterações. Se houver 5 clientes diferentes conectados com o mesmo nome de usuário, um deles enfrentará o dilema de rastrear qual dos 5 disparou a consulta. Outras soluções ilusórias que encontrei incluem alterar a tabela CDC com o seguinte comando:

ALTER TABLE cdc.schema_table_CT 
ADD HostName nvarchar(50) NULL DEFAULT(HOST_NAME())

No entanto, isso retorna o nome do host do servidor no qual a consulta foi acionada, e não o nome do host do cliente que aciona a consulta.

Existe uma maneira de contornar este problema? Algo que ajudaria a registrar o nome do host ou o endereço IP (ou algum outro tipo de identidade exclusiva) do cliente. Eu não quero usar gatilhos, pois diminui a velocidade do sistema, o CDC também gera tabelas de sistema, portanto, ter um gatilho aparentemente não é possível.

Ritesh Bhakre
fonte

Respostas:

4

Não tenho certeza sobre o CDC, mas se o login tiver, view server state permissionvocê poderá usar as DMVs para obter algumas informações.

Isso é fornecido no Books Online aqui . Mudei a consulta para adicionar colunas, o que lhe daria IP address:

SELECT 
    c.session_id, c.net_transport, c.encrypt_option, c.auth_scheme,
    s.host_name, s.program_name, s.client_interface_name,
    c.local_net_address, c.client_net_address, s.login_name, s.nt_domain, 
    s.nt_user_name, s.original_login_name, c.connect_time, s.login_time 
FROM sys.dm_exec_connections AS c
JOIN sys.dm_exec_sessions AS s
    ON c.session_id = s.session_id
WHERE c.session_id = SPID;  --session ID you want to track
Shanky
fonte
4

Quando você diz, "sem o uso de gatilhos", que quer dizer qualquer gatilhos ou apenas remar-by-gatilhos de linha em tabelas?

Eu pergunto, porque você pode conseguir o que deseja com o uso criterioso da CONTEXT_INFO()função, mas precisaria garantir que a SET CONTEXT_INFOchamada fosse correta antes das operações.

Um lugar para fazer isso pode ser um gatilho de logon no nível do servidor (ou seja, não um gatilho no banco de dados / no objeto), como:

USE master
GO
CREATE TRIGGER tr_audit_login
ON ALL SERVER 
WITH EXECUTE AS 'sa'
AFTER LOGON
AS BEGIN
    BEGIN TRY

        DECLARE @eventdata XML = EVENTDATA();

        IF @eventdata IS NOT NULL BEGIN
            DECLARE @spid INT;
            DECLARE @client_host VARCHAR(64);
            SET @client_host    = @eventdata.value('(/EVENT_INSTANCE/ClientHost)[1]',   'VARCHAR(64)');
            SET @spid           = @eventdata.value('(/EVENT_INSTANCE/SPID)[1]',         'INT');

            -- pack the required data into the context data binary
            -- (spid is just an example of packing multiple data items in a single field: you would probably use @@SPID at the point of use, instead)
            DECLARE @context_data VARBINARY(128);
            SET @context_data = CONVERT(VARBINARY(4),  @spid)
                              + CONVERT(VARBINARY(64), @client_host);

            -- persist the spid and host into session-level memory
            SET CONTEXT_INFO @context_data;             
        END

    END TRY
    BEGIN CATCH
        /* do better error handling here...
         * logon trigger can lock all users out of server, so i am just swallowing everything
         */
        DECLARE @msg NVARCHAR(4000) = ERROR_MESSAGE();
        RAISERROR('%s', 10, 1, @msg) WITH LOG;
    END CATCH
END

Você pode adicionar a restrição padrão à sua tabela, para armazenar o contexto (para velocidade de inserção):

ALTER TABLE cdc.schema_table_CT 
ADD ContextInfo varbinary(128) NULL DEFAULT(CONTEXT_INFO())

Depois disso, você pode consultar essa ContextInfocoluna com um pouco de fatia e dados:

SELECT *
    ,spid = CONVERT(INT, SUBSTRING(ContextInfo, 1, 4))
    ,client = CONVERT(VARCHAR(64), SUBSTRING(ContextInfo, 5, 64))
FROM cdc.schema_table_CT

Tecnicamente, você pode fazer isso SUBSTRINGe CONVERToutras coisas como parte de sua restrição padrão e apenas armazenar o IP do cliente lá, mas pode ser mais rápido armazenar todo o contexto lá (como é feito em todos INSERT) e extrair apenas os valores em um SELECTquando você precisar deles.

Eu posso estar inclinado a agrupar todas as minhas chamadas SUBSTRINGe CONVERTem uma função com valor de tabela em linha de linha única, o que faria CROSS APPLYquando necessário. Isso mantém a lógica de descompactação em um só lugar:

CREATE FUNCTION fn_context (
    @context_info VARBINARY(128)
)
RETURNS TABLE
AS RETURN (
    SELECT
         spid = CONVERT(INT, SUBSTRING(@context_info, 1, 4))
        ,client = CONVERT(VARCHAR(64), SUBSTRING(@context_info, 5, 64))
)
GO

SELECT * 
FROM cdc.schema_table_CT s
CROSS APPLY dbo.fn_context(s.ContextInfo) c

Observe que CONTEXT_INFOé apenas um de 128 bytes VARBINARY. Se você precisar de mais dados do que pode caber em 128 bytes, eu criaria uma tabela para armazenar todos esses dados, insira como linha para essa 'sessão' na tabela no gatilho de logon e defina CONTEXT_INFOo valor da chave substituta dessa tabela

Você também deve observar que, como é apenas uma restrição padrão, é trivial para um usuário com privilégios adequados substituir esses dados de contexto na tabela em repouso. Obviamente, o mesmo vale para todas as outras colunas nas tabelas no estilo 'audit'.

Seria bom se pudesse ser uma coluna computada persistente, em vez de um padrão, mas a CONTEXT_INFO()função é não determinística, por isso é um não-go (você pode usar alguns FUNCTIONtruques em torno de um VIEW, mas eu não )

Também é trivial para esse usuário com acesso suficiente se chamar SET CONTEXT_INFOe estragar o seu dia (por exemplo, com valores falsos ou injeção armazenada especialmente criada), portanto, trate o conteúdo com suspeita e cuidado, codifique-o antes da exibição e lide com exceções bem.

Quanto ao nome do host, acho que o ClientHostelemento EVENTDATA()fornece o endereço IP (ou um <local machine>indicador). Embora você possa tecnicamente usar o CLR para fazer pesquisas de DNS reverso no nome do host, elas tendem a ser muito lentas para todos INSERT, por isso recomendo que não o façam.

Se você precisar ter um nome de host, convém usar uma tarefa do SQL Agent para preencher periodicamente uma tabela separada com as concessões atuais do servidor DHCP local ou do arquivo de zona DNS, como um processo fora de banda, e LEFT JOINpara isso em consultas futuras (ou agrupe em um escalar FUNCTIONpara fornecer um valor a uma restrição padrão, para um determinado momento).

Novamente, você deve observar que, se o aplicativo tiver algum tipo de componente voltado para o público, os endereços IP e os nomes de host não são confiáveis ​​(por exemplo, devido ao NAT). Mesmo que não seja voltado para o público, há um determinado componente baseado em tempo na maioria dos mapas de IP / nome de host, que talvez você precise levar em consideração.

Por fim, antes de implementar seu gatilho de login, pode valer a pena ativar a conexão administrativa dedicada do servidor. Se o gatilho de login for interrompido de alguma forma, poderá impedir que todos os usuários efetuem login (incluindo as contas sysadmin):

USE master
GO
-- you may want to do this, so you have a back-out if the login trigger breaks login
EXEC sp_configure 'remote admin connections', 1 
GO
RECONFIGURE
GO

Se você ficar bloqueado, o DAC pode ser usado para descartar ou desativar o gatilho de login:

C:\> sqlcmd -S localhost -d master -A
1> DISABLE TRIGGER tr_audit_login ON ALL SERVER
2> GO
jimbobmcgee
fonte
3

Dê uma olhada no bug de conexão : Abaixo está o trecho relevante dele

Esse comportamento é por design. O CDC foi projetado para expor as seguintes informações sobre uma alteração: colunas atualizadas, tipo de operação e informações de transação. Não foi projetado como uma solução de auditoria. Foi criado para permitir soluções eficientes de transferência e carga de extração (ETL) por meio de um carregamento incremental de dados, essencial para reduzir o tempo total de ETL. Seu principal objetivo é expor "o que mudou" e não quem, quando ... Por isso, recomendo o recurso de auditoria do SQL.

No momento, não há plano de transformar o CDC em uma solução de auditoria.

Jens W.
fonte