65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2016 年 9 月 5 日

MIT

5分钟阅读

viewsIcon

20394

引言

在我之前的帖子中,我讨论了如何使用领域事件来捕获领域内部的“变化”。在这篇文章中,我将提供一个示例,说明如何创建一个关联 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() 将完美完成这项工作)并在您的堆栈中使用它。 

© . All rights reserved.