1

We are looking for the optimal sql login audit solution, with usable filtering.

Thus far we have looked into Server Audits and profiler but have concluded that extended events look most promising, unless anyone can show us otherwise.

Question is, is there any good way to filter unnecessary login events? e.g. when I connect using SSMS, immediatly about 10 login events are added and continue to pile up if I leave SSMS connected to a instance. Why is that?

This is our current implementation:

USE master;
GO
-- Create the Event Session
IF EXISTS
    (
        SELECT
                  *
            FROM  sys.server_event_sessions
            WHERE name = 'ServerLoginAudit'
    )
    DROP EVENT SESSION ServerLoginAudit ON SERVER;
GO
EXECUTE xp_create_subdir 'D:\audits\Sessions';
GO
CREATE EVENT SESSION ServerLoginAudit
    ON SERVER
    ADD EVENT sqlserver.login
        (SET
             collect_database_name = (1)
           , collect_options_text = (1)
         ACTION
             (
                 sqlserver.sql_text
               , sqlserver.nt_username
               , sqlserver.server_principal_name
               , sqlserver.client_hostname
               , package0.collect_system_time
               , package0.event_sequence
               , sqlserver.database_id
               , sqlserver.database_name
               , sqlserver.username
               , sqlserver.session_nt_username
               , sqlserver.client_app_name
               , sqlserver.session_id
               , sqlserver.context_info
               , sqlserver.client_connection_id
             )
        )

    ADD TARGET package0.event_file
        (SET filename = N'D:\audits\Sessions\ServerLoginAudit.xel', max_file_size = (20), max_rollover_files = (2))
    WITH
        (
            STARTUP_STATE = OFF
          , TRACK_CAUSALITY = ON
        );
/* start the session */
ALTER EVENT SESSION ServerLoginAudit ON SERVER STATE = START;
GO
1

Reason for the numerous connections

Those are connections caused by SSMS to provide you mainly the visual structure of object explorer. Also, When you're using SSMS, each new tab you open is a different session (and more connections - see The multiple connections of SSMS). IntelliSense also creates extra connections as you'll see if you remove the predicate on the query I suggested as a workaround.

try connecting with sqlcmd Utility like this on a CMD prompt:

sqlcmd -A

When I connected with SQLCMD only one log was reported on the Extended Event Session you provided.

Workaround

Instead of filtering the data you collect I suggest you filter the data you query afterwards, here's one way to do that:

WITH
    event_data AS (
        SELECT CAST(event_data AS XML) AS event_data_xml
        FROM fn_xe_file_target_read_file('D:\audits\Sessions\ServerLoginAudit*.xel',NULL,NULL,NULL)
    )
    , event_data_fields AS (
        SELECT 
             DATEADD(ms, -DATEPART(ms, event_data_xml.value('(/event/@timestamp)[1]', 'datetime')), event_data_xml.value('(/event/@timestamp)[1]', 'datetime')) AS interval
            , event_data_xml.value('(/event/data[@name="database_name"]/value)[1]', 'varchar(250)') AS database_name
            , event_data_xml.value('(/event/action[@name="client_app_name"]/value)[1]', 'nvarchar(250)') AS client_app_name
            , event_data_xml.value('(/event/action[@name="client_hostname"]/value)[1]', 'nvarchar(250)') AS client_hostname
            , event_data_xml.value('(/event/action[@name="server_principal_name"]/value)[1]', 'nvarchar(250)') AS server_principal_name
            , event_data_xml.value('(/event/action[@name="nt_username"]/value)[1]', 'nvarchar(250)') AS nt_username
        FROM event_data
    )
SELECT 
      interval
    , database_name
    , client_app_name
    , client_hostname
    , server_principal_name
    , nt_username
FROM event_data_fields
WHERE 
    client_app_name NOT IN ('SQLServerCEIP', 'Microsoft SQL Server Management Studio - Transact-SQL IntelliSense')
GROUP BY
      interval
    , database_name
    , client_app_name
    , client_hostname
    , server_principal_name
    , nt_username;

With that method, if you don't find the info you seek at first, you can reduce the predicates to show all data collected and have a more accurate report of all the connections that happened at the time. Also, if you filter the data you collect by the application name, it would leave a breach on your audit because one can Change the Application Name of SSMS and login to your server unnoticed.

2
  • Just to clarify, I meant the connections are unnecessary in the sense that I only wanted to capture the user connection one time, not from all of the SSMS components. – Bergmeister Mar 10 at 9:33
  • @Bergmeister I see. I updated my answer to be more accurate and added code that might help you. Please, check it again. – Ronaldo Mar 10 at 13:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.