如何关联 IIS、应用程序和 SQL Server 审核日志以实现全栈审核。





5.00/5 (6投票s)
引言
在我之前的帖子中,我讨论了如何使用领域事件来捕获领域内部的“变化”。在这篇文章中,我将提供一个示例,说明如何创建一个关联 ID 来关联 IIS、领域和 SQL Server 审核日志。
解决方案要求
- 作为一名安全分析师,我希望能够看到请求来自何处,以便识别恶意用户,从而可以阻止该用户或将该用户识别信息传递给公司。
- 作为一名安全分析师,我希望能够看到用户的请求更改了什么,以便识别软件错误或恶意用户行为。
- 作为一名软件工程师,我不想在应用程序中记录 Web 请求元数据或 SQL 请求,因为我不想维护这些代码和数据。
问题
您如何关联以下日志?
IIS W3C 日志
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2016-09-04 20:24:22 ::1 GET / - 80 - ::1 Mozilla/5.0+(Windows+NT+6.3)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/52.0.2743.116+Safari/537.36 - 200 0 0 612
请注意,这里没有唯一 ID。
应用程序领域事件日志
<d2p1:eventdto>
<d2p1:args xmlns:d5p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d5p1:keyvalueofstringstring>
<d5p1:key>FirstName</d5p1:key>
<d5p1:value>Zan</d5p1:value>
</d5p1:keyvalueofstringstring>
<d5p1:keyvalueofstringstring>
<d5p1:key>LastName</d5p1:key>
<d5p1:value>Kavtaskin</d5p1:value>
</d5p1:keyvalueofstringstring>
<d5p1:keyvalueofstringstring>
<d5p1:key>Email</d5p1:key>
<d5p1:value>zan.kavtaskin@someemail.com</d5p1:value>
</d5p1:keyvalueofstringstring>
<d5p1:keyvalueofstringstring>
<d5p1:key>Country</d5p1:key>
<d5p1:value>1</d5p1:value>
</d5p1:keyvalueofstringstring>
</d2p1:args>
<d2p1:created>2016-09-03T15:55:52.4805906+01:00</d2p1:created>
<d2p1:type>CustomerCreated</d2p1:type>
</d2p1:eventdto>
SQL Server 审核日志
那么,如何关联上述日志呢?显而易见的答案是某种形式的关联 ID。这种方法在您的应用程序内部是有意义的,因为您对其有控制权。但是,IIS 呢?每个 Web 请求的元数据在命中您的应用程序之前(有时甚至在之后)就会被写入日志。
解决方案
1. 创建关联 ID 哈希
IIS 会在日志中捕获 IP 地址、用户代理、路径、方法等变量(见上文)。由于您知道您在 IIS 日志中存储了什么,您可以在应用程序内的请求标头中获取这些变量,并创建一个 W3C 关联 ID 哈希。
public interface IRequestCorrelationIdentifier
{
string CorrelationID { get; }
}
public class W3CWebRequestCorrelationIdentifier : IRequestCorrelationIdentifier
{
public string CorrelationID { get; private set; }
public W3CWebRequestCorrelationIdentifier()
{
/* #Customise your correlation ID here
* More request identification variables you add easier
* it's going to be to find the relevant W3C request when you hash it
*
* Below is just an example of variables and hash algorithm that you can use:
*/
string rawCorrelationID = string.Join("_",
HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"],
HttpContext.Current.Request.Params["LOGON_USER"],
HttpContext.Current.Request.UserAgent != null ?
HttpContext.Current.Request.UserAgent.ToString().Replace(" ", "+") : "-",
HttpContext.Current.Request.Path,
HttpContext.Current.Request.QueryString.ToString() ?? "-",
new DateTime(HttpContext.Current.Timestamp.Ticks).ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss")
);
StringBuilder hashBuilder = new StringBuilder();
using (MD5 md5 = MD5.Create())
{
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(rawCorrelationID));
for (int i = 0; i < hash.Length; i++)
hashBuilder.Append(hash[i].ToString("X2"));
}
this.CorrelationID = hashBuilder.ToString();
}
}
想看一个工作示例吗?它就在 GitHub 上:就在这里。
您可能会想,有什么意义?现在您只是存储了一个哈希关联 ID,这个哈希没有存储在 IIS 日志中。嗯,当您需要调查问题时,您会知道问题发生在哪几天,您只需要对特定日期范围内的 IIS 日志运行类似的代码来生成哈希码,然后您就可以找到匹配的关联 ID(还有一些细节,请参阅底部的“搜索 W3C 日志”部分)。
2. 注册关联标识符
然后,IRequestCorrelationIdentifier 可以与您的依赖注入框架以每个 Web 请求的生命周期进行注册。这将确保该 Web 请求管道中的所有组件获得相同的关联 ID。
container.Register(Component.For<IRequestCorrelationIdentifier>().ImplementedBy<WebRequestCorrelationIdentifier>().LifeStyle.PerWebRequest);
想看一个工作示例吗?它就在 GitHub 上:就在这里。
3. 使用关联 ID 记录所有内容
现在您可以准备在应用程序中使用 IRequestCorrelationIdentifier 了。以下是如何将其与领域事件日志记录结合使用:
public class DomainEventHandle<TDomainEvent> : Handles<TDomainEvent> where TDomainEvent : DomainEvent { IDomainEventRepository domainEventRepository; IRequestCorrelationIdentifier requestCorrelationIdentifier; public DomainEventHandle(IDomainEventRepository domainEventRepository, IRequestCorrelationIdentifier requestCorrelationIdentifier) { this.domainEventRepository = domainEventRepository; this.requestCorrelationIdentifier = requestCorrelationIdentifier; } public void Handle(TDomainEvent @event) { @event.Flatten(); @event.CorrelationID = this.requestCorrelationIdentifier.CorrelationID; this.domainEventRepository.Add(@event); }
想看一个工作示例吗?它就在 GitHub 上:就在这里。
4. 启用 IIS 日志记录
5. 启用 SQL Server 审计
Microsoft 最近发布了 SQL Server 审计功能。它会记录对数据库执行的所有原始 SQL 语句。由于您现在有了关联 ID,您所要做的就是获取关联 ID 并搜索您的 XEL 文件。这是一个 XEL 过滤器屏幕示例,我正在搜索一个关联 ID。
如果在“statement”字段中找到关联 ID,它将返回相关行。
通过单击行,您将获得审计事件的细分。
这非常强大,因为您可以识别所有更改,现在您可以将它们全部关联起来。
搜索 W3C 日志
可能会发生以下情况:
- IIS 会在您的应用程序处理完 Web 请求后几秒钟才记录它。
- 您的应用程序会在 IIS 记录您的 Web 请求后几秒钟才处理它。
这有什么意义?关联 ID 哈希码是在应用程序内部使用日期时间变量生成的。您的应用程序不知道 IIS 使用了哪个时间戳。这意味着当您搜索 IIS W3C 日志并哈希相同的变量时,您可能找不到预期的关联 ID。IIS 和您的应用程序之间的延迟仅为 +/- 2 秒(这是我测试时发现的)。因此,当您搜索 IIS W3C 日志时,只需生成 4 个额外的哈希码并一起搜索即可。
这是一个例子。
您的应用程序已哈希以下内容:-_/_index=aa23ab2a-5d9a-4018-99e6-c50d2abfbad4_2016-09-03 23:04:21
它产生了以下哈希:93cad82c735b913dea5c722500ea6d22
当您搜索 93cad82c735b913dea5c722500ea6d22 时可能一无所获。如果没有,只需哈希以下内容 +/- 2 秒:
-_/_index=aa23ab2a-5d9a-4018-99e6-c50d2abfbad4_2016-09-03 23:04:19 ->(-2)
-_/_index=aa23ab2a-5d9a-4018-99e6-c50d2abfbad4_2016-09-03 23:04:20 ->(-1)
-_/_index=aa23ab2a-5d9a-4018-99e6-c50d2abfbad4_2016-09-03 23:04:22 ->(+1)
-_/_index=aa23ab2a-5d9a-4018-99e6-c50d2abfbad4_2016-09-03 23:04:23 ->(+2)
结论
优点
- 无需创建自定义 IIS 日志格式化程序
- 无需在您自己的应用程序中写出请求元数据,IIS 日志记录会为您处理这些。
- 伪造关联 ID 非常困难,因为它是在服务器端创建的,而不是从客户端传递的。
- 事件和日志可以使用相同的关联 ID 进行存储。
- 同样的方法不仅可用于生成 IIS 的哈希,还可用于生成队列等其他上游系统的哈希。
缺点
- 当您搜索 W3C 日志时,您可能需要生成 4 个额外的哈希来查找您的关联 ID。
这是一个低维护的全栈日志记录解决方案,您只需要编写和管理最少的代码和数据。
如果您不太关心 IIS W3C 日志关联,那么只需生成一个随机关联 ID(Guid.NewGuid()
将完美完成这项工作)并在您的堆栈中使用它。