1. 程式人生 > >SQL Server 錯誤日誌過濾(ERRORLOG)

SQL Server 錯誤日誌過濾(ERRORLOG)

一、背景

  有一天我發現SQL Server伺服器的錯誤日誌中包括非常多關於sa使用者的登陸錯誤資訊:“Login failed for user 'sa'. 原因: 評估密碼時出錯。[客戶端: XX.XX.XX.XX]”。可是我很久之前就已經禁用了sa使用者,怎麼還會有那麼多的sa使用者登陸資訊呢?我猜想是有人在暴力破解我們資料庫的sa使用者的密碼;關於這種攻擊,大家有沒好的解決方案呢?

  我查找了一些資料,暫時沒有找到好的解決方案。我只想到一個暫時緩解壓力的辦法,那就是從錯誤資訊中統計出登陸sa使用者的客戶端IP地址,再設定防火牆把這些IP過濾掉。

  那現在如何解決IP的統計呢?使用SSMS是根本無法進行統計,因為錯誤日誌的記錄太多了。SSMS開啟錯誤日誌的方式如下圖Figure1和Figure2所示;

clip_image001

(Figure1:SQL Server 日誌)

clip_image003

(Figure2:sa登陸資訊)

經過資料的查詢,發現有兩種方式可以對錯誤日誌進行過濾:

1. 利用SQL Server系統儲存過程xp_readerrorlog進行過濾;

2. 利用預設跟蹤(Default Trace)進行過濾;

二、xp_readerrorlog實現錯誤日誌過濾

(一) 關於錯誤日誌的基本操作可以參考:SQL Server錯誤日誌收縮(ERRORLOG)。首先了解錯誤日誌檔案的路徑和大小,可以通過Figure3的方式找到檔案,檢視大小。

clip_image004

(Figure3:SQL Server ErrorLog檔案資訊)

  除了Figure3直接找到錯誤日誌的方式之外,我們還可以通過執行儲存過程EXEC xp_enumerrorlogs返回表的形式進行檢視資訊,如Figure4所示。xp_enumerrorlogs儲存過程還提供引數,預設值為1(如果沒有提供引數表示傳入的引數為1),2的時候表示查詢SQL Server 代理錯誤日誌列表,如Figure13所示。

--Script1:獲取[SQL Server]錯誤日誌列表
EXEC xp_enumerrorlogs
EXEC xp_enumerrorlogs 1

clip_image005

(Figure4:SQL Server 錯誤日誌列表)

(二) 接下來了解系統儲存過程:xp_readerrorlog,它一共有7個引數,分別是:

1. 存檔編號(0~99)

2. 日誌型別(1為SQL Server日誌,2為SQL Server Agent日誌)

3. 查詢包含的字串

4. 查詢包含的字串

5. LogDate開始時間

6. LogDate結束時間

7. 結果排序,按LogDate排序(Desc、Asc)

(三) 接著講解xp_readerrorlog系統儲存過程的運用:

  1. 如果你想查詢當前SQL Server錯誤日誌檔案(當前正在寫入錯誤資訊的檔案)的內容,請執行SQL指令碼:EXEC xp_readerrorlog,存檔編號的預設值為0,它相當於開啟檔案ERRORLOG(路徑可參考Figure3),如果想讀取其它的歷史錯誤日誌檔案,直接填寫對應的存檔編號就可以了(存檔編號可以參考Figure4),下面3條SQL語句的執行效果是一樣的:

--Script2:查詢當前SQL Server日誌資訊
EXEC xp_readerrorlog
EXEC xp_readerrorlog 0
EXEC xp_readerrorlog 0,1

clip_image006

(Figure5:當前SQL Server錯誤日誌)

查詢存檔編號為n(n Between 0 And 99)的SQL Server日誌資訊:Exec xp_readerrorlog n,n為什麼只能0~99?可參考:SQL Server錯誤日誌收縮(ERRORLOG)

  2. 我們繼續學習其它引數的使用,檢視SQL Server日誌歷史存檔為1檔案中,發生的時間為2013-05-09至2013-05-10之間的錯誤,排序方式為時間的倒排序,為了滿足上面的要求,執行下面的SQL指令碼:

--Script3:檢視SQL Server日誌存檔為1,時間範圍為XX,按照時間反排序
EXEC xp_readerrorlog 1,1,NULL,NULL,'2013-05-09','2013-05-10','DESC'

clip_image008

(Figure6:錯誤日誌時間過濾)

  3. 檢視SQL Server日誌歷史存檔為1檔案中,錯誤內容裡面包含字串:'Login failed for user ''sa''',並且包括字串:'192.168.1.5',發生的時間為2013-05-09至2013-05-10之間的錯誤,排序方式為時間的倒排序,為了滿足上面的要求,執行下面的SQL指令碼:

--Script4:檢視SQL Server日誌存檔為,包含XX字串,並且包含%%字串,時間範圍為XX,按照時間反排序
EXEC xp_readerrorlog 1,1,'Login failed for user ''sa''','192.168.1.5','2013-05-09','2013-05-10','DESC'

clip_image010

(Figure7:錯誤日誌字串+日期過濾)

三、Default Trace實現錯誤日誌過濾

2. 要過濾錯誤日誌,那首先就要知道在預設跟蹤中那個型別trace_event_id是代表錯誤日誌的,在Read Default Trace中描述了關於trace_event_id的資訊:If you are interested in what the default trace has been setup to capture you can run this (Note you cannot edit the default trace!)。

--Script5:trace_event
SELECT *  
FROM fn_trace_geteventinfo(1) tg   
INNER JOIN sys.trace_events te ON tg.[eventid] = te.[trace_event_id]  
INNER JOIN sys.trace_columns tc ON tg.[columnid] = tc.[trace_column_id]
WHERE te.name like '%login%'

clip_image011

(Figure8:trace_event_id資訊)

  通過上面Script5的SQL指令碼,我們知道需要監控EventName為:Audit Login Failed,trace_event_id為20的資訊,如Figure8所示。另外檢視方式:sp_trace_setevent,在這裡你也可以找到關於Login Failed描述所對應的Event number。

3. 下面我們來實現使用fn_trace_gettable讀取log.trc檔案的方式來過濾錯誤日誌:

--Script6:返回登陸錯誤資訊
-- =============================================
-- Author:        <聽風吹雨>
-- Create date:    <2013.05.03>
-- Description:    <讀取、過濾log.trc檔案>
-- Blog:        <http://www.cnblogs.com/gaizai/>
-- =============================================
DECLARE @tracefile NVARCHAR(MAX) 
SET @tracefile = (SELECT LEFT([path],LEN([path])-CHARINDEX('\',REVERSE([path])))+ '\log.trc' FROM sys.traces WHERE [is_default] = 1) 
 
SELECT 
 gt.[ServerName] 
,gt.[DatabaseName] 
,gt.[SPID] 
,gt.[StartTime] 
,gt.[ObjectName] 
,gt.[objecttype] [ObjectTypeID]--http://msdn.microsoft.com/en-us/library/ms180953.aspx 
,sv.[subclass_name] [ObjectType] 
,e.[category_id] [CategoryID] 
,c.[Name] [Category] 
,gt.[EventClass] [EventID] 
,e.[Name] [EventName] 
,gt.[LoginName] 
,gt.[ApplicationName] 
,gt.[TextData] 
FROM fn_trace_gettable(@tracefile, DEFAULT) gt 
LEFT JOIN sys.trace_subclass_values sv ON gt.[eventclass] = sv.[trace_event_id] AND sv.[subclass_value] = gt.[objecttype] 
INNER JOIN sys.trace_events e ON gt.[eventclass] = e.[trace_event_id] 
INNER JOIN sys.trace_categories c ON e.[category_id] = c.[category_id] 
WHERE gt.[spid] > 50 
AND gt.[databasename] = 'master'
AND e.category_id = 8 --category 8表示安全
AND gt.[starttime] >= '2013-05-13 12:00:00'
AND gt.[starttime] <= '2013-05-14'
AND e.trace_event_id = 20
ORDER BY StartTime DESC

clip_image013

(Figure9:Default Trace返回的錯誤日誌)

4. 為了讓預設跟蹤Default Trace和xp_readerrorlog返回的資料進行對比,我們再次執行xp_readerrorlog,使用引數儘量與Default Trace保持一致。

--Script7:對比
EXEC xp_readerrorlog 0,1,'Login failed for user ''sa''','','2013-05-13 12:00:00','2013-05-14','DESC'

clip_image015

(Figure10:xp_readerrorlog返回的錯誤日誌)

對比Figure9與Figure10的資訊,發現返回的記錄數基本上是相同的。

四、補充說明

  1. xp_enumerrorlogs和xp_readerrorlog除了可以檢視【SQL Server錯誤日誌】還可以檢視【SQL Server 代理錯誤日誌】。在SSMS中可以直接檢視代理錯誤日誌,如Figure11所示,它的路徑和檔案如Figure12所示,xp_enumerrorlogs值為2的時候表示查詢SQL Server 代理錯誤日誌列表,如Figure13所示。

--Script5:獲取[SQL Server 代理]錯誤日誌列表
EXEC xp_enumerrorlogs 2

clip_image016

(Figure11:SQL Server Agent日誌)

clip_image017

(Figure12:SQL Server Agent ErrorLog檔案資訊)

clip_image018

(Figure13:SQL Server 代理錯誤日誌列表)

  值得注意的是【SQL Server 代理錯誤日誌】並沒有SQLAGENT.0這個檔案,Figure13中的當前 = Figure14中的SQLAGENT.OUT = Figure15中的存檔#10記錄;如果要確認這一點,你可以通過日誌檔案的內容和檔案的大小進行確認。

  2. 由於我的資料庫需要外網訪問,所以沒有辦法做很多的改動,比如換資料庫的埠,已經有太多的運用程式在使用了。(這個可以通過解決方案設計解決:SQL Server 資料庫帳號密碼安全設計

  3. 由於是sa無法在【是否允許連線到資料庫引擎】選擇【拒絕】選項,如Figure14所示。有沒好的辦法可以防止sa的暴力破解呢?雖然這樣不會造成資料庫建立連結,但是這樣會造成:消耗網路流量;消耗資料庫伺服器的效能;消耗SQL Server日誌容量;消耗ERRORLOG日誌檔案帶來的磁碟IO(雖然可以通過Figure15那樣設定不記錄登陸資訊,但是這樣日誌記錄就沒有意義了);

clip_image019

(Figure14:帳號設定)

clip_image020

(Figure15:設定日誌記錄)

  北京-宋沄劍提到把sa修改掉,修改後只是提示資訊變為:“Login failed for user 'sa'. 原因: 找不到與所提供的名稱相匹配的登入名。 [客戶端: 60.190.118.153]”,問題還是存在。(修改之前錯誤資訊是:Login failed for user 'sa'. 原因: 評估密碼時出錯。 [客戶端: 60.190.118.153])

  4. 使用sp_helptext是無法找到系統儲存過程xp_enumerrorlogs和xp_readerrorlog的原始碼的,這個是為什麼呢?

--檢視儲存過程或者檢視原始碼
exec sp_helptext 'xp_enumerrorlogs'
exec sp_helptext 'xp_readerrorlog'

clip_image021

(Figure16:sp_helptext)

  6. 如果不想在log.trc中看到有關Login failed for user 'sa'.的錯誤日誌,可以修改預設跟蹤嗎?在sp_trace_setevent (Transact-SQL)中提到:

1) 如果將 on 設定為 1,並且 column_id 為 NULL,則將事件設定為 ON 並清除所有列。如果 column_id 不為 NULL,則將該事件的列設定為 ON。

2) 如果將 on 設定為 0,並且 column_id 為 NULL,則將事件設定為 OFF 並清除所有列。如果 column_id 不為 NULL,則將列設定為 OFF。

clip_image022

(Figure17:修改預設跟蹤錯誤)

  7. 關於使用xp_readerrorlog讀取ERROR檔案記錄內容,有沒方法一次性讀取所有的ERROR檔案的資料呢?使用UNION ALL?

五、參考文獻