트리거를 사용하지 않고 SQL Server에서 쿼리를 실행하는 클라이언트의 ID를 찾으십니까?


11

현재 CDC (Change Data Capture) 를 사용하여 데이터 변경 사항을 추적하고 있으며 변경 한 쿼리를 제출하는 클라이언트의 호스트 이름과 IP 주소를 추적하고 싶습니다. 동일한 사용자 이름으로 5 개의 서로 다른 클라이언트가 로그인 한 경우 5 명 중 어느 것이 쿼리를 실행했는지 추적해야 할 문제가 있습니다. 내가 찾은 다른 의심스러운 솔루션에는 다음 명령으로 CDC 테이블을 변경하는 것이 포함됩니다.

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

그러나 이렇게하면 쿼리를 시작한 클라이언트의 호스트 이름이 아니라 쿼리가 시작된 서버의 호스트 이름이 반환됩니다.

이 문제를 해결할 방법이 있습니까? 클라이언트의 호스트 이름 또는 IP 주소 (또는 다른 종류의 고유 한 ID)를 기록하는 데 도움이되는 것. 트리거를 사용하고 싶지 않습니다. 시스템 속도를 늦추고 CDC도 시스템 테이블을 생성하므로 트리거를 갖는 것은 불가능합니다.

답변:


4

CDC에 대해 잘 모르겠지만 로그인이 view server state permission있으면 DMV를 사용하여 정보를 얻을 수 있습니다.

이것은 온라인 설명서 에서 제공 됩니다 . 쿼리를 변경하여 열을 추가했습니다 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

4

언제 무슨 뜻이야, "트리거를 사용하지 않고"라고 어떤 트리거를하거나 행 단위 트리거 테이블에?

이 때문에 부탁 할 수 는 사리 분별을 이용하여 원하는 것을 얻을 수 CONTEXT_INFO()기능,하지만 당신은 확인해야합니다 SET CONTEXT_INFO귀하의 작업이 수행 정확하게 전에 호출했다.

이를 위해 서버 수준 로그온 트리거 (예 : 데이터베이스 / 개체 수준 트리거가 아님)가있을 수 있습니다.

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

그런 다음 컨텍스트를 저장하기 위해 테이블에 기본 제한 조건을 추가 할 수 있습니다 (삽입 속도).

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

일단 그것을 ContextInfo얻으면 약간의 슬라이스 앤 주사위로 해당 열을 쿼리 할 수 ​​있습니다 .

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

기술적으로, 당신은 할 수 SUBSTRINGCONVERT기본 제약 조건의 일환으로 물건을 그냥 IP가 클라이언트를 저장하지만, 전체 컨텍스트를 저장하기 위해 더 빨리 할 수있다 (그것은 모든에서 수행 될 때 INSERT), 그리고 단지의 값을 추출 SELECT필요할 때

모든 행 SUBSTRINGCONVERT호출을 단일 행 인라인 테이블 반환 함수 로 래핑 하는 것이 CROSS APPLY필요할 수 있습니다. 이렇게하면 언 패킹 논리가 한 곳에 유지됩니다.

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

참고 CONTEXT_INFO만 128 바이트입니다 VARBINARY. 128 바이트에 들어갈 수있는 것보다 많은 데이터가 필요한 경우 모든 데이터를 보유 할 테이블을 만들고 로그온 트리거의 테이블에 해당 '세션'에 대한 행으로 삽입하고 해당 테이블 CONTEXT_INFO의 서로 게이트 키 값으로 설정 합니다.

또한 기본 제약 조건 일 뿐이므로 적절한 권한이있는 사용자가 미사용 테이블의 해당 컨텍스트 데이터를 덮어 쓰는 것은 쉽지 않습니다. 물론 '감사'스타일 테이블의 다른 모든 열에 대해서도 마찬가지입니다.

기본이 아닌 지속적인 계산 열이 될 수 있다면 좋을 것입니다. 그러나 CONTEXT_INFO()함수는 비 결정적이므로 FUNCTION실패 하지 않습니다 (당신은 주위에 약간의 속임수 를 사용할 수는 VIEW있지만, 그렇지 않습니다. ).

또한 SET CONTEXT_INFO자신 에게 전화를 걸고 하루를 엉망으로 만들 수 있는 충분한 액세스 권한을 가진 사용자에게는 사소한 일입니다 (예 : 가짜 값 또는 특수 제작 된 저장 주입으로). 잘.

호스트 이름에 관해서는의 ClientHost요소가 EVENTDATA()IP 주소 (또는 <local machine>표시기) 를 제공 한다고 생각합니다 . 기술적으로 CLR을 사용하여 역방향 DNS 조회를 호스트 이름으로 다시 수행 할 수는 있지만이 방법은 매번 수행하기에는 너무 느린 경향이 있으므로 그렇게하지 않는INSERT 것이 좋습니다 .

이 경우 호스트 이름을 가지고, 당신은 정기적으로 해당 지역의 DHCP 서버 나 DNS 영역 파일에서 현재 임대와 별도의 테이블을 채우려면 대역 외 과정과 같은 SQL 에이전트 작업을 사용하려면, 그리고 수도 LEFT JOIN에서와 향후 쿼리 (또는 FUNCTION특정 시점에 대한 기본 제약 조건에 값을 제공하기 위해 스칼라 로 래핑 ).

응용 프로그램에 공용 구성 요소가 있으면 IP 주소와 호스트 이름을 신뢰할 수 없습니다 (예 : NAT로 인해). 공개 대상이 아니더라도 대부분의 IP / 호스트 이름 맵에는 특정 시간 기반 구성 요소가 있으므로 고려해야합니다.

마지막으로 로그인 트리거를 구현하기 전에 서버의 전용 관리자 연결을 설정하는 것이 좋습니다. 로그인 트리거가 중단되면 모든 사용자가 로그인하지 못하게 할 수 있습니다 (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

잠기면 DAC를 사용하여 로그인 트리거를 삭제하거나 비활성화 할 수 있습니다.

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

3

연결 버그를 살펴보십시오 . 아래는 관련 스 니펫입니다.

이것은 의도적으로 설계된 동작입니다. CDC는 업데이트 된 열, 작업 유형 및 트랜잭션 정보와 같은 변경 사항에 대한 정보를 제공하도록 설계되었습니다. 감사 솔루션으로 설계되지 않았습니다. 전체 ETL 시간을 줄이는 데 중요한 증분 데이터로드를 통해 효율적인 ETL (Extract Transfer and Load) 솔루션을 구현하기 위해 개발되었습니다. 주요 목표는 언제, 누구가 아니라 "변경된 내용"을 공개하는 것입니다. SQL 감사 기능을 권장합니다.

현재로서는 감사 솔루션에서 CDC를 변환 할 계획이 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.