扩展事件 - sqlserver.process_login_finish 未触发?

Ril*_*jor 7 extended-events sql-server-2016

我们正在尝试查看客户端是否能够访问数据库服务器,因为它收到错误:

[DBNETLIB][ConnectionOpen (Connect()).]SQL Server 不存在或访问被拒绝。

该错误在一段时间内不会发生,这通常是客户端无法访问目标服务器的结果(例如,数据库服务器名称不正确)。该错误发生在 Web 应用程序中以及使用 Windows Server 2003 Web Edition 操作系统工具测试 ODBC 连接时。

为了尝试确定导致问题的原因,我们想查看连接尝试是否到达数据库服务器。我们认为我们可以使用扩展事件来监控登录尝试。

sqlserver.process_login_finish是 SQL Server 2016 中的一个新事件,它“在服务器完成登录处理(成功或失败)时生成”。

我们使用以下代码创建了一个事件会话:

CREATE EVENT SESSION [Test Login Audit] ON SERVER 
ADD EVENT
    sqlserver.process_login_finish
    (
        ACTION
        (
            package0.collect_system_time,
            sqlserver.client_app_name,
            sqlserver.client_hostname,
            sqlserver.nt_username
        )
    )
ADD TARGET package0.ring_buffer;
GO

ALTER EVENT SESSION [Test Login Audit] ON SERVER
  STATE = START;
GO
Run Code Online (Sandbox Code Playgroud)

然后我们多次连接到服务器,使用 Windows 和 SQL 身份验证,包括故意为 SQL 用户输入错误的密码。

然后我们查询扩展事件数据如下:

SELECT name, target_name, CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet
JOIN sys.dm_xe_sessions AS xe
   ON (xe.address = xet.event_session_address)
WHERE xe.name = 'Test Login Audit';
Run Code Online (Sandbox Code Playgroud)

但是,我们发现没有处理过的事件:

<RingBufferTarget truncated="0" processingTime="0" totalEventsProcessed="0" eventCount="0" droppedCount="0" memoryUsed="0" />
Run Code Online (Sandbox Code Playgroud)

然后我们从 Aaron Bertrand创建了这个登录失败扩展事件会话

CREATE EVENT SESSION FailedLogins
ON SERVER
 ADD EVENT sqlserver.error_reported
 (
   ACTION 
   (
     sqlserver.client_app_name,
     sqlserver.client_hostname,
     sqlserver.nt_username
    )
    WHERE severity = 14

    -- added this line:
      AND error_number = 18456

      AND state > 1 -- removes redundant state 1 event
  )
  ADD TARGET package0.ring_buffer;
GO

ALTER EVENT SESSION FailedLogins ON SERVER
  STATE = START;
GO
Run Code Online (Sandbox Code Playgroud)

然后我们为 SQL 用户登录使用了不正确的密码。然后我们查询了它的数据:

SELECT name, target_name, CAST(xet.target_data AS xml)
FROM sys.dm_xe_session_targets AS xet
JOIN sys.dm_xe_sessions AS xe
   ON (xe.address = xet.event_session_address)
WHERE xe.name = 'FailedLogins';
Run Code Online (Sandbox Code Playgroud)

并发现了捕获的事件:

<RingBufferTarget truncated="0" processingTime="0" totalEventsProcessed="3" eventCount="3" droppedCount="0" memoryUsed="1323">
  <event name="error_reported" package="sqlserver" timestamp="2017-07-06T21:27:49.407Z">
    <data name="error_number">
      <type name="int32" package="package0" />
      <value>18456</value>
    </data>
    <data name="severity">
      <type name="int32" package="package0" />
      <value>14</value>
    </data>
    <data name="state">
      <type name="int32" package="package0" />
      <value>8</value>
    </data>
    <data name="user_defined">
      <type name="boolean" package="package0" />
      <value>false</value>
    </data>
    <data name="category">
      <type name="error_category" package="sqlserver" />
      <value>4</value>
      <text>LOGON</text>
    </data>
    <data name="destination">
      <type name="error_destination" package="sqlserver" />
      <value>0x0000001c</value>
      <text>BUFFER, ERRORLOG, EVENTLOG</text>
    </data>
    <data name="is_intercepted">
      <type name="boolean" package="package0" />
      <value>true</value>
    </data>
    <data name="message">
      <type name="unicode_string" package="package0" />
      <value>Login failed for user 'zzzzzzzz'. Reason: Password did not match that for the login provided. [CLIENT: 10.nnn.nnn.nnn]</value>
    </data>
    <action name="nt_username" package="sqlserver">
      <type name="unicode_string" package="package0" />
      <value />
    </action>
    <action name="client_hostname" package="sqlserver">
      <type name="unicode_string" package="package0" />
      <value>WS449</value>
    </action>
    <action name="client_app_name" package="sqlserver">
      <type name="unicode_string" package="package0" />
      <value>Microsoft SQL Server Management Studio - Query</value>
    </action>
  </event>
</RingBufferTarget>
Run Code Online (Sandbox Code Playgroud)

(删除了 2 个额外的事件并混淆了一些信息)

然而,我们在 event 上创建的“Test Login Audit”事件会话中仍然没有任何内容sqlserver.process_login_finish

所以扩展事件系统和环形缓冲区正在工作。并且正在发生登录。

那么为什么我们没有收到任何sqlserver.process_login_finish事件呢?我们是否误解了“登录”是什么?这还不是一个完整的功能吗?

我们从@@VERSION 得到这个:

Microsoft SQL Server 2016 (SP1) (KB3182545) - 13.0.4001.0 (X64) 
    Oct 28 2016 18:17:30 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows Server 2012 R2 Standard 6.3 <X64> (Build 9600: ) (Hypervisor)
Run Code Online (Sandbox Code Playgroud)

2017-07-07 更新:

对于那些好奇的人,我们已经解决了最初的连接问题。默认情况下,SQL Server 的命名实例使用动态端口进行侦听。我们的防火墙只允许端口 1433。

来自微软关于配置端口的文档

如果启用,SQL Server 数据库引擎的默认实例会侦听 TCP 端口 1433。数据库引擎和 SQL Server Compact 的命名实例配置为动态端口。这意味着它们会在 SQL Server 服务启动时选择一个可用端口。当您通过防火墙连接到命名实例时,将数据库引擎配置为侦听特定端口,以便可以在防火墙中打开相应的端口。

我们将 SQL Server 的端口调整为 1433,连接问题得到解决。

(动态端口分配至少需要UDP 端口 1434 以允许初始端口查询,然后防火墙必须嗅探并自动允许生成的动态分配端口,就像许多可以为 FTP PASV 命令做的一样。我不确定如果有的话可以为这样的 SQL 端口协商做到这一点。)

然而,由于这主要是关于某些未触发的扩展事件的问题,我打算让这个问题悬而未决。