🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 采用大数据和机器学习来保护您的在线服务 **[艾莉森溶胶](https://msdn.microsoft.com/zh-cn/magazine/ee532098.aspx?sdmr=AlissonSol&sdmi=authors)  [唐 Ankney](https://msdn.microsoft.com/zh-cn/magazine/ee532098.aspx?sdmr=DonAnkney&sdmi=authors)  [Eugene Bobukh](https://msdn.microsoft.com/zh-cn/magazine/ee532098.aspx?sdmr=EugeneBobukh&sdmi=authors)** **[下载代码示例](https://msdn.microsoft.com/zh-cn/magazine/msdnmag0115)** 目前有几种方法保护在线服务,从安全开发生命周期的操作流程对事件作出迅速反应。在线服务的主要资产之一,经常被忽视 — — 大数据创建的请求日志和业务事件监视。这篇文章将探讨使用率数据处理和机器学习 (ML) 技术来提高安全性,基于保护 Microsoft 应用程序中的在线资产的经验 & 服务组 (ASG),包括 Bing,Bing 的广告和 MSN 等服务。 大多数在线服务创建几个流的记录的数据。固然没有标准分类的各种测量您可以存储有关的服务,当你正在寻求安全问题的数据,可以大致归类为使用率数据或操作数据。使用率数据包括关于由其目标受众服务使用的任何记录的值。一个常见的例子是对 Web 站点的请求的日志项: ~~~ #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 2014-10-27 20:46:57 127.0.0.1 GET /search q=election+results&form=PRUSEN&mkt=en-us 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+6.4;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko - 200 0 0 5265 ~~~ 这种类型的日志条目包含数据只是关于所请求的资源,客户端浏览器、 返回代码和完成请求所需的时间。更复杂的服务可以丰富与派生的信息,比如地理位置或特定于应用程序的信息,如用户标识 (对于已登录的用户) 的使用率数据。会没有使用率数据没有实际的用户,除了或许用于测试和监控代理。 业务数据是指服务器和服务操作的测量。这包括 CPU 利用率或温度、 磁盘空间、 网络传输速率,应用程序异常、 内存故障和登录,只要打开服务器,启动服务的类似因素。在现代数据中心,日志信息通常包括不仅计算设备,如空调的测量、 派驻人员和游客在区内包含敏感数据,门被打开和关闭和类似的业务安全标准所需的信息方面。 这篇文章中的代码示例将集中处理使用率数据。不过,您可以应用的大多数原则概述,并证明在这里识别漏洞利用业务数据。你也可以提高你的识别安全事件关联使用数据和业务数据的机会。 ## 进攻的终结点 改变为一个大型的在线服务的速度很难来保护使用只有典型的安全开发生命周期做法,例如代码审查和静态分析工具。数以千计的变化都承诺每个月。经常有至少几个几百个实验"飞行"在任何给定的点。这些实验呈现新的特点,来选择要收集反馈信息广泛发布之前的用户。除了以下良好发展做法和有渗透测试团队不断设法找出漏洞,至关重要的是要尽可能多的漏洞发现尽可能自动化。 在 2014 年年底,附近微软 Bing 服务生成数百兆兆字节的使用率数据每天,测井达数千亿美元的请求。它是安全承担一些这些请求是实际攻击,试图找出或漏洞。一个典型的查询到 Bing 是向服务发送一个 URL 请求: ~~~ http://www.bing.com/search?q=election+results&form=PRUSEN&mkt=en-us ~~~ 在此示例中,用户搜索"选举结果"。有两个其他 URL 中的参数识别起源的要求和市场设置 (在本例中,该值指示用户语言英语和美国) 的 Web 窗体。你可能会理解这一点作为"搜索"应用程序在 Bing 的域中,参数 q,形式与市场的呼唤所有此类要求表示在一个规范的格式,如下所示: ~~~ http://www.bing.com/search?q=[]&form=[]&mkt=[] ~~~ 有内冰域回答类似请求的其他应用程序。一个请求要求的视频格式的"选举结果"将是: ~~~ http://www.bing.com/videos?q=election+results&form=PRUSEN&mkt=en-us ~~~ 随着在线服务的增长,新的应用程序和功能添加动态 — — 一些方便和其他的兼容性。不同的格式通常允许相同的请求。Bing 视频也会接受这项要求: ~~~ http://videos.bing.com/?q=election+results&form=PRUSEN&mkt=en-us ~~~ 假设你可以从使用率日志列表与规范的所有请求到服务,你可以然后探测器试图注入参数值的已知恶意有效载荷的漏洞。例如,入侵者可以使用下列请求验证是否 Bing 视频应用程序很容易受到跨站点脚本 (XSS) 在查询参数中: ~~~ http://www.bing.com/videos?q=<script>alert("XSS") </script>&form=PRUSEN&mkt=en-us ~~~ 入侵者的安全漏洞扫描还将测试中响应的恶意负载注入其他参数,则在所有可能的组合。一旦发现了一个漏洞,可以发起攻击。攻击 Url 通常包含在垃圾邮件,希望一小部分用户会不小心点击链接。有些用户甚至可能怀疑 Url,其中包含 JavaScript 关键字。然而,编码的请求使更难及时识别攻击: ~~~ http://www.bing.com/videos?&form=PRUSEN&mkt=en-us&q=%3CscRipt%3Ealert(%22XSS%22)%3C%2FScriPT%3E ~~~ 您可以编写应用程序接受规范请求到服务的列表作为输入,注入恶意有效载荷为每种可能的脆弱性和检测从服务问题答案,如果这次袭击成功。你可以找到代码漏洞的几种个别的"探测器"(XSS、 SQL 注入和开放重定向) 在线。在这篇文章,我们将重点放在寻找"攻击面"对在线服务的使用率数据日志。 ## 处理环境 博客通常分布在几个机器制作的顺序日志文件读取效率极高 (如果文件被分割成跨不同的存储设备在分布式的文件系统中的更好)。这使得处理博客 MapReduce 框架一个伟大的应用程序。 对于这个示例,我们将放到博客微软 Azure Blob 根据相同的容器,称为 InputContainer。作为一种处理平台,我们会使用 Azure HDInsight 流 MapReduce 作业。有良好的信息已经在线上可用如何设置和配置 HDInsight 集群。在这篇文章中解释的代码将生成二进制文件应放置在容器中 HDInsight 群集,简称为 ClusterBinariesContainer 可以访问。作为代码执行,并处理输入,它会在另一个容器称为 ClusterOutputContainer,以及状态信息保存到 ClusterStatusContainer 中创建的输出。一个可视化的 Azure HDInsight 处理配置所示**图 1**。 ![](https://box.kancloud.cn/2016-01-07_568e4d6691417.png) **图 1 天青 HDInsight 处理环境** 您需要替换中的占位符名称**图 1** 与您的特定配置的值。您可以设置这些配置文件中。Windows PowerShell 脚本将创建并执行 HDInsight 作业将读取 XML 配置文件中所示**图 2**。配置文件之后, 你会最有可能执行该脚本的使用率数据分析从内 Azure PowerShell 提示符下,正确配置了您 Azure 的帐户具有授权才能访问存储和计算服务 (见得到 AzureAccount 和添加 AzureAccount cmdlet 帮助)。 **图 2 Windows PowerShell 脚本 XML 配置文件** ~~~ <?xml version="1.0" encoding="utf-8"?> <Configuration>   <SubscriptionName>Your-SubscriptionName</SubscriptionName>   <ClusterName>Your-ClusterName</ClusterName>   <ClusterStorageAccountName>Your-ClusterStorageAccountName     </ClusterStorageAccountName>   <ClusterBinariesContainer>Your-ClusterBinariesContainer     </ClusterBinariesContainer>   <MapperBinary>UsageDataMapper.exe</MapperBinary>   <ReducerBinary>UsageDataReducer.exe</ReducerBinary>   <ClusterOutputContainer>Your-ClusterOutputContainer</ClusterOutputContainer>   <ClusterStatusContainer>Your-ClusterStatusContainer</ClusterStatusContainer>   <InputStorageAccountName>Your-InputStorageAccountName     </InputStorageAccountName>   <InputStorageAccountKey>Your-InputStorageAccountKey</InputStorageAccountKey>   <InputContainer>Your-InputContainer</InputContainer>   <DeployBinaries>true</DeployBinaries>   <DeployFlavor>Release</DeployFlavor>   <JobTimeOut>3600</JobTimeOut> </Configuration> ~~~ ## 映射到规范要求 获取使用 MapReduce 的在线服务的受攻击面加工环境包括创建一个映射器的应用程序从博客中提取的 Url 并将它们转换成标准形式。该值为减速机,然后将消除重复成为关键。这是示例字计数应用程序中可用的 HDInsight 中使用的同一原则。删除任何注释和验证代码,下面的代码演示映射应用程序的主入口点: ~~~ public static void Main(string[] args) {   Console.SetIn(new StreamReader(args[0]));   string inputLogLine;   while ((inputLogLine = Console.ReadLine()) != null)   {     string outputKeyAndValues =       ExtractKeyAndValuesFromLogLine(inputLogLine);     Console.WriteLine(outputKeyAndValues);   } } ~~~ 此代码遍历每个输入行并提取的唯一的键,以及任何具有互补的价值有关的被解决的问题。举个例子,假如你正在寻找的最常见的用户查询,关键将传递查询参数的值。原始日志行如下所示: ~~~ #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 2014-10-27 20:46:57 127.0.0.1 GET /search q=election+results&form=PRUSEN&mkt=en-us 80 - 127.0.0.1 Mozilla/5.0+(Windows+NT+6.4;+WOW64;+Trident/7.0;+Touch;+rv:11.0)+like+Gecko - 200 0 0 5265 ~~~ 列 cs-uri 和 cs uri 查询有你需要有经过解析来获取请求的规范形式的相关信息 (示例代码不包括多个宿主 pro­处理)。要提取每个日志行的键和值的函数所述**图 3**。 **图 3 从日志行提取键和值的函数** ~~~ private static string ExtractKeyAndValuesFromLogLine(string inputLogLine) {   StringBuilder keyAndValues = new StringBuilder();   string[] inputColumns = inputLogLine.Split(DataFormat.MapperInputColumnSeparator);   string uriReference = inputColumns[DataFormat.MapperInputUriReferenceColumn];   string uriQuery = inputColumns[DataFormat.MapperInputUriQueryColumn];   string parameterNames = ExtractParameterNamesFromQuery(uriQuery);   // Key = uriReference + separator + parameterNames   keyAndValues.Append(uriReference);   keyAndValues.Append(DataFormat.ReferenceFromQuerySeparator);   keyAndValues.Append(parameterNames);   keyAndValues.Append(DataFormat.MapperOutputColumnSeparator);   keyAndValues.Append(DataFormat.OneOccurrence);   return keyAndValues.ToString(); } ~~~ 唯一缺少逻辑涉及从查询列中提取的参数名称。要执行此任务的代码所示**图 4**。该函数的输入 — — 以前提供的示例行 — — 将会像这样一个字符串: ~~~ q=election+results&form=PRUSEN&mkt=en-us ~~~ **图 4 函数来从查询获得只是参数的名称** ~~~ private static string ExtractParameterNamesFromQuery(string query) {   StringBuilder sb = new StringBuilder();   // Go through each parameter adding to output string   string[] nameValuePairs = query.Split(DataFormat.ParametersSeparator);   Array.Sort(nameValuePairs, StringComparer.InvariantCultureIgnoreCase);   List<string> uniqueParameterNames = new List<string>();   foreach (string nameValuePair in nameValuePairs)   {     int indexOfSeparatorParameterNameFromValue =       nameValuePair.IndexOf(DataFormat.ParameterNameFromValueSeparator);     string paramName = nameValuePair;     paramName = nameValuePair.Substring(0,       indexOfSeparatorParameterNameFromValue);     uniqueParameterNames.Add(paramName);     sb.Append(paramName);     sb.Append(DataFormat.ParameterNameFromValueSeparator);     sb.Append(DataFormat.OneOccurrence);     sb.Append(DataFormat.ParametersSeparator);   }   return sb.ToString(); } ~~~ 在示例代码中使用的规范形式将删除参数值、 排序的参数名称和它转变为一个仍然有效的查询字符串: ~~~ form=1&mkt=1&q=1& ~~~ 排序的参数名称有助于避免工作重复,因为 Web 请求不依赖于参数顺序。用于参数值的占位符是"1",而不是"[]",因为它是更短。它还可能与其他的东西像计数的参数将出现在所有的请求参数组合的次数,如中所示用于**图 4**。 ## 减少攻击面 映射代码按顺序读取日志行,然后为每个输出的键和值。MapReduce 有一个"结合"的阶段,由减速机代码用相同的密钥对加工组装的所有记录。如果输入的日志有做搜索查询的几行,到目前为止,那些产生相同的输出: ~~~ search?form=1&mkt=1&q=1&         1 search?form=1&mkt=1&q=1&         1 search?form=1&mkt=1&q=1&         1 ~~~ **图 5** 已经减速机代码大纲。它读取输入的行并拆分那些入键和值。它直到关键的变化,保持一个计数器,然后输出结果。 **图 5 减速器主回路** ~~~ public static void Main(string[] args) {   string currentKey, previousKey = null;   int count = 0;   Console.SetIn(new StreamReader(args[0]));   string inputLine;   while ((inputLine = Console.ReadLine()) != null)   {     string[] keyValuePair =       inputLine.Split(DataFormat.ReducerInputColumnSeparator);     currentKey = keyValuePair[0];     if (currentKey != previousKey)     {       Console.WriteLine(DataFormat.ReducerOutputLineFormat, previousKey, count);       count = 1;       previousKey = currentKey;     }     else count++;   }   Console.WriteLine(DataFormat.ReducerOutputLineFormat, previousKey, count); } ~~~ 您可以轻松地修改代码和用于其他目的本文中提供的脚本。更改函数 ExtractKeyAndValuesFromLogLine 有参数值作为键,你会有用值使用频率的分布。在其当前的窗体,则输出将攻击面,显示的请求频率与归一化的应用程序路径的列表: ~~~ search?form=1&mkt=1&q=1&         3 video?form=1&mkt=1&q=1&           10 ~~~ ## 理解服务交通 攻击面已经将价值以帮助您了解正在发生与您的服务,即使你不执行主动渗透性测试,以暴露安全漏洞。虽然请求频率变化每小时,每日一周内,与其他季节性的因素,正常的行为特征随时间变化释放,或甚至协同攻击。例如,Bing 会收到数以亿计每日请求数。攻击表面列表通常有数以十万计的每一天的值。即使预期并不是所有此类路径。**图 6** 总结了攻击面上在典型的一天上发现了什么。第一行指示到 89.8%规范路径的通常请求通信量,10 量最高。未来的十大路径添加达 6.3%的请求计数 (或前 20 名的 96.1%)。那些真正顶尖的应用程序服务。一切共计少于 4%。这种请求的模式是一个网站用银团的内容,如 MSN.com 非常不同的。 **图 6 典型分布的请求路径为必应在 2013 年** | 典型的路径 | 百分比 | |---|---|---| | 前 10 条 | 89.8 | | 前 20 条 | 96.1 | | 用路径 < = 1000 个请求 | 99.9 | | 用路径 < = 100 个请求 | 99.6 | | 用路径 < = 10 个请求 | 97.6 | | 路径与 = 1 的请求 | 67.5 | 它是特别有趣地注意到大约三分之二的请求到独特的路径。一些这些请求可能来自攻击者试图探测可能触发某些功能的应用程序参数。然而在线服务的本质会生成大量的此类通信量。链接到您的服务存储几年前仍处于可能被人类激活状态或自动化的流程。同时寻求攻击者,你可能发现需要有一种兼容性模式为旧的 Url,和自动重定向到新版本的应用程序。这是一个很好的业务结果。 开发该攻击的应用程序是一段旅程,你应该小心。假设你的探测器都完美的会到您需要适当节流的服务现在施加负荷。您需要避免产生拒绝服务攻击或影响对真正的用户性能。此外,至关重要的是要避免许多误报。如果发生这种情况,从攻击服务事件报告将很快就会被忽略。 ## 学习从服务数据 毫升,可以自动完成多个进程,就很难进行直接编码指令或规则。例如,很难想象会觉察到一个人的计算机视觉应用程序的代码是在镜头前。贴标数千幅图像的深度信息,然而,在微软的 Kinect 团队后能够"训练"ML 模块,这样做的足够的精度。标记的深度图像指示不仅是人类的存在,而且也是身体的位置,使学习的过程。 生成请求已知类别的攻击服务 (XSS、 SQL 注入等等) 自动化过程要用于 ML 方法评价在线交通的重要组成部分。它会生成大量的综合地面真相。检查使用日志,可以轻松地识别已知攻击服务由在某个时间的所有此类攻击的要求。他们现在正在与用户请求,因为其中没有却已知的分类 (正常或恶意请求) 混合。 若要创建一个分层的真正匹配通信量,击中该服务的数据,你必须了解该通信量的特点。生成实验样品有 0.1%的接收 1000 亿请求服务的使用情况数据一天仍导致 1 亿的请求。只有合成数据可以帮助创建一个初始地面的真理。 假设你有高质量地面真相和适当的工具,概述了 ML 解决方案,以评估用户请求的学习过程的迭代周期在**图 7**。入手综合数据在地面的真理,你可以做实验和开球毫升模块进行分类的请求中的训练过程 (分为如正常人,XSS、 SQL 注入等等) 或使 (指示请求属于一个或多个类别的信心) 的回归。可以部署此毫升模块作为解决方案的一部分然后可开始接收评价要求。输出然后有一个评分的过程,它将表明是否毫升模块正确确定请求 (真阳性和真正的底片),错过了可疑请求 (假阴性) 或生成虚假警报 (假阳性)。 ![](https://box.kancloud.cn/2016-01-07_568e4d66a3354.png) **图 7 学习周期,以创建一个机器学习基于解决方案** 如果最初的实验产生足够毫升模块基于合成数据良好,该模块应该是相当准确的与几个不正确地评估实际的用户请求。然后可以正确标签那些被错误地评估并将它们添加到地面真相。几个更多的实验和训练现在应该生成一个新的 ML 模块恢复精度。当你仔细地重复这一过程,初始的合成数据变得更小的部分,在培训过程中,使用的事实依据和迭代 ML 模块更好地准确地评估用户的请求。对于附加的验证,您可以使用毫升模块对脱机应用程序检查使用日志和识别恶意请求。经过充分的发展,您可以部署毫升模块在线评估请求在真正的时间,并防止攻击过命中后端应用程序。 ## 总结 而你应该继续遵循坚实的发展过程 (包括安全开发生命周期),你应该还需要承担你在线服务可能受到攻击任何点。使用率日志可以为您提供关于如何发生这种攻击有深度的信息。知道你的受攻击面,将帮助您主动攻击您的服务,以查明和关闭漏洞之前他们剥削。攻击服务然后创建综合地面真相,启用的 ML 技术培训毫升模块,以评估服务请求使用的建筑。建筑攻击服务并非微不足道的工作,但近期和长期的业务成果远远超过所花的投资。