DDoS 救援:我们如何进行压力和负载测试

DDoS 救援:我们如何进行压力和负载测试

Variti 开发针对机器人程序和 DDoS 攻击的防护,并进行压力和负载测试。 在 HighLoad++ 2018 会议上,我们讨论了如何保护资源免受各种类型的攻击。 简而言之:隔离系统的各个部分,使用云服务和 CDN,并定期更新。 但如果没有专业公司,您仍然无法应对保护:)

在阅读正文之前,您可以阅读简短的摘要 在会议网站上.
如果您不喜欢阅读或只想观看视频,我们的报告录音位于下面的剧透部分。

报告视频录制

许多公司已经知道如何进行负载测试,但并非所有公司都进行压力测试。 我们的一些客户认为他们的网站是无懈可击的,因为他们拥有高负载系统,并且可以很好地防止攻击。 我们证明这并不完全正确。
当然,在进行测试之前,我们会获得客户的许可,并签字盖章,在我们的帮助下,无法对任何人进行DDoS攻击。 测试是在客户选择的时间进行的,此时其资源的流量最小,并且访问问题不会影响客户端。 此外,由于测试过程中总会出现问题,因此我们会不断与客户联系。 这使您不仅可以报告所取得的结果,还可以在测试期间更改某些内容。 测试完成后,我们总是会起草一份报告,指出发现的缺陷并提出消除网站弱点的建议。

我们的工作方式

测试时,我们模拟僵尸网络。 由于我们与不在我们网络上的客户合作,为了确保测试不会因触发限制或保护而在第一分钟结束,我们不是从一个 IP 提供负载,而是从我们自己的子网提供负载。 另外,为了创建显着的负载,我们拥有自己的相当强大的测试服务器。

假设

太多并不意味着好
导致资源失效的负载越少越好。 如果您可以使网站在每秒一个请求甚至每分钟一个请求时停止运行,那就太好了。 因为根据卑鄙法则,用户或攻击者会不小心陷入这个特定的漏洞。

部分失败优于完全失败
我们总是建议使系统异构。 此外,值得在物理层面上将它们分开,而不仅仅是通过容器化。 在物理分离的情况下,即使站点出现故障,也很有可能不会完全停止工作,用户将继续访问至少部分功能。

良好的建筑是可持续发展的基础
资源的容错能力及其承受攻击和负载的能力应该在设计阶段就确定下来,事实上,在记事本中绘制第一个流程图的阶段就应该确定。 因为如果出现致命错误,将来纠正它们是可能的,但这是非常困难的。

不仅代码要好,配置也要好
很多人认为一个好的开发团队是容错服务的保证。 一个好的开发团队确实是必要的,但是还必须有好的运营,好的DevOps。 也就是说,我们需要能够正确配置 Linux 和网络、在 nginx 中正确编写配置、设置限制等的专家。 否则,该资源仅在测试中才能正常工作,而在生产中某些时候一切都会崩溃。

负载测试和压力测试之间的差异
负载测试使您能够识别系统功能的限制。 压力测试的目的是发现系统中的弱点,用于破坏这个系统,看看它在某些部分发生故障的过程中会如何表现。 在这种情况下,在压力测试开始之前,客户通常仍然不知道负载的性质。

L7攻击的显着特征

我们通常将负载类型分为L7和L3&4级别的负载。 L7 是应用程序级别的负载,大多数情况下它仅指 HTTP,但我们指的是 TCP 协议级别的任何负载。
L7 攻击具有某些显着特征。 首先,它们是直接到达应用程序的,即不太可能通过网络手段体现出来。 此类攻击使用逻辑,因此非常高效地消耗 CPU、内存、磁盘、数据库等资源,且流量较小。

HTTP洪水

在任何攻击的情况下,创建负载比处理负载更容易,对于 L7 来说也是如此。 区分攻击流量和合法流量并不总是那么容易,大多数情况下这可以通过频率来完成,但如果一切都计划正确,则不可能从日志中了解攻击在哪里以及合法请求在哪里。
作为第一个示例,请考虑 HTTP 洪水攻击。 从图中可以看出,此类攻击通常非常强大;在下面的示例中,峰值请求数超过每分钟 600 万次。

DDoS 救援:我们如何进行压力和负载测试

HTTP Flood 是创建负载的最简单方法。 通常,它需要某种负载测试工具(例如 ApacheBench),并设置请求和目标。 采用这种简单的方法,很有可能会遇到服务器缓存,但很容易绕过它。 例如,向请求添加随机字符串,这将迫使服务器不断提供新页面。
另外,不要忘记创建负载过程中的用户代理。 流行测试工具的许多用户代理都被系统管理员过滤,在这种情况下,负载可能根本无法到达后端。 您可以通过将浏览器中或多或少有效的标头插入到请求中来显着改善结果。
HTTP Flood 攻击虽然简单,但也有其缺点。 首先,需要大量的电力来产生负载。 其次,此类攻击非常容易检测,尤其是来自一个地址的攻击。 结果,系统管理员甚至提供商级别立即开始过滤请求。

搜索什么

为了减少每秒的请求数而不损失效率,您需要表现出一点想象力并探索该站点。 因此,您不仅可以加载通道或服务器,还可以加载应用程序的各个部分,例如数据库或文件系统。 您还可以在网站上查找进行大型计算的位置:计算器、产品选择页面等。 最后,网站经常会出现某种 PHP 脚本生成数十万行页面的情况。 此类脚本还会显着增加服务器负载,并可能成为攻击目标。

在哪里看

当我们在测试之前扫描资源时,我们首先当然会查看网站本身。 我们正在寻找各种输入字段、重型文件 - 一般来说,所有可能给资源带来问题并减慢其运行速度的东西。 Google Chrome 和 Firefox 中的普通开发工具可以在这方面提供帮助,显示页面响应时间。
我们还扫描子域。 例如,有一个在线商店 abc.com,它有一个子域 admin.abc.com。 最有可能的是,这是一个具有授权的管理面板,但如果您对其施加负载,它可能会给主要资源带来问题。
该站点可能有一个子域 api.abc.com。 这很可能是移动应用程序的资源。 该应用程序可以在 App Store 或 Google Play 中找到,安装特殊的接入点,剖析 API 并注册测试帐户。 问题在于,人们常常认为任何受授权保护的东西都不会受到拒绝服务攻击。 据说,授权是最好的验证码,但事实并非如此。 创建 10-20 个测试帐户很容易,但通过创建它们,我们可以访问复杂且不加掩饰的功能。
当然,我们会查看历史记录、robots.txt、WebArchive、ViewDNS,并查找资源的旧版本。 有时,开发人员已经推出了 mail2.yandex.net,但旧版本 mail.yandex.net 仍然存在。 此 mail.yandex.net 不再受支持,开发资源不会分配给它,但它继续消耗数据库。 因此,使用旧版本,您可以有效地利用后端的资源以及布局背后的所有资源。 当然,这种情况并不总是发生,但我们仍然经常遇到这种情况。
自然,我们分析所有的请求参数和cookie结构。 比如说,您可以将一些值转储到 cookie 内的 JSON 数组中,创建大量嵌套,并使资源工作不合理的长时间。

搜索负载

研究网站时首先想到的是加载数据库,因为几乎每个人都会进行搜索,但不幸的是,对于几乎每个人来说,数据库的保护都很薄弱。 由于某些原因,开发人员对搜索没有给予足够的重视。 但这里有一个建议——你不应该发出相同类型的请求,因为你可能会遇到缓存,就像HTTP洪水的情况一样。
对数据库进行随机查询也并不总是有效。 最好创建与搜索相关的关键字列表。 如果我们回到在线商店的例子:假设该网站销售汽车轮胎,并允许您设置轮胎半径、汽车类型和其他参数。 因此,相关单词的组合将迫使数据库在更复杂的条件下工作。
此外,值得使用分页:搜索返回搜索结果的倒数第二页比第一页要困难得多。 也就是说,借助分页,您可以稍微分散负载。
下面的示例显示了搜索负载。 可以看到,从测试的第一秒开始,以每秒十个请求的速度,站点就宕机了,没有任何响应。

DDoS 救援:我们如何进行压力和负载测试

如果没有搜索呢?

如果没有搜索,这并不意味着该网站不包含其他易受攻击的输入字段。 该字段可以是授权。 如今,开发人员喜欢制作复杂的哈希值来保护登录数据库免受彩虹表攻击。 这很好,但是这样的哈希会消耗大量的 CPU 资源。 大量的错误授权会导致处理器故障,从而导致站点停止工作。
网站上存在各种用于评论和反馈的表格,这是向那里发送非常大的文本或简单地造成大规模洪水的原因。 有时网站接受附加文件,包括 gzip 格式。 在本例中,我们获取一个 1TB 文件,使用 gzip 将其压缩为几个字节或千字节,然后将其发送到站点。 然后将其解压,就得到了一个非常有趣的效果。

Rest API

我想稍微关注一下像 Rest API 这样的流行服务。 保护 Rest API 比普通网站要困难得多。 即使是针对密码暴力破解和其他非法活动的简单保护方法也不适用于 Rest API。
Rest API 很容易被破坏,因为它直接访问数据库。 同时,这种服务的失败会给企业带来相当严重的后果。 事实上,Rest API 通常不仅用于主网站,还用于移动应用程序和一些内部业务资源。 如果这一切都失败了,那么其影响比简单的网站故障要强得多。

加载大量内容

如果我们被要求测试一些没有复杂功能的普通单页应用程序、登陆页面或名片网站,我们会寻找大量内容。 例如,服务器发送的大图像、二进制文件、pdf 文档 - 我们尝试下载所有这些。 此类测试可以很好地加载文件系统并堵塞通道,因此是有效的。 也就是说,即使你不关闭服务器,以低速下载大文件,你也只会堵塞目标服务器的通道,然后就会发生拒绝服务。
此类测试的示例显示,在 30 RPS 的速度下,站点停止响应或产生第 500 个服务器错误。

DDoS 救援:我们如何进行压力和负载测试

不要忘记设置服务器。 你经常会发现有人买了一台虚拟机,在那里安装了 Apache,默认配置了一切,安装了 PHP 应用程序,下面你可以看到结果。

DDoS 救援:我们如何进行压力和负载测试

这里负载达到了根部并且仅为 10 RPS。 我们等了 5 分钟,服务器崩溃了。 确实,目前尚不完全清楚他为何摔倒,但有一种假设是他的记忆太多,因此停止了反应。

基于波

在过去的一两年里,波浪攻击变得相当流行。 这是因为许多组织购买了某些硬件来进行 DDoS 防护,这需要一定的时间来积累统计数据才能开始过滤攻击。 也就是说,它们不会在前 30-40 秒内过滤攻击,因为它们会积累数据并学习。 因此,在这 30-40 秒内,您可以在站点上启动大量资源,以致资源将停留很长时间,直到所有请求都被清除。
在下面的攻击中,有 10 分钟的间隔,之后新的、经过修改的攻击部分到达。

DDoS 救援:我们如何进行压力和负载测试

也就是说,防御方学习并开始过滤,但攻击的新的、完全不同的部分到来,防御方再次开始学习。 事实上,过滤停止工作,保护变得无效,并且站点不可用。
Wave攻击的特点是峰值时值非常高,在L7的情况下可以达到每秒十万或一百万个请求。 如果我们谈论 L3 和 4,那么如果以数据包计算的话,可能会有数百吉比特的流量,或者相应地,数百 mpps。
此类攻击的问题在于同步。 这些攻击来自僵尸网络,需要高度同步才能创建非常大的一次性峰值。 而且这种协调并不总是有效:有时输出是某种抛物线峰值,看起来相当可悲。

不只是 HTTP

除了 L7 层的 HTTP 之外,我们还喜欢利用其他协议。 通常,常规网站,尤其是常规主机,都会突出显示邮件协议和 MySQL。 邮件协议承受的负载比数据库少,但它们也可以非常有效地加载,最终导致服务器上的 CPU 过载。
我们非常成功地利用了 2016 年的 SSH 漏洞。 现在这个漏洞已经几乎所有人都被修复了,但这并不意味着负载不能提交到SSH。 能。 授权负载巨大,SSH 几乎耗尽了服务器上的整个 CPU,然后网站因每秒一两个请求而崩溃。 因此,基于日志的这一个或两个请求无法与合法负载区分开。
我们在服务器中打开的许多连接也仍然具有相关性。 以前是 Apache 犯了这个错误,现在 nginx 实际上也犯了这个错误,因为它通常是默认配置的。 nginx 可以保持打开的连接数量是有限的,所以我们打开这个数量的连接,nginx 就不再接受新的连接,结果导致网站无法工作。
我们的测试集群有足够的 CPU 来攻击 SSL 握手。 原则上,正如实践所示,僵尸网络有时也喜欢这样做。 一方面,很明显你不能没有 SSL,因为 Google 结果、排名、安全性。 另一方面,不幸的是 SSL 存在 CPU 问题。

L3&4层

当我们谈论L3&4级别的攻击时,我们通常谈论的是链路级别的攻击。 这样的负载几乎总是可以与合法负载区分开来,除非它是 SYN 洪水攻击。 安全工具的 SYN-flood 攻击的问题在于其数量巨大。 L3&4 的最大值为 1,5-2 Tbit/s。 即使对于甲骨文和谷歌等大公司来说,这种流量也很难处理。
SYN 和 SYN-ACK 是建立连接时使用的数据包。 因此,SYN-flood 很难与合法负载区分开来:不清楚这是一个过来建立连接的 SYN,还是泛洪的一部分。

UDP泛洪

通常,攻击者不具备我们所拥有的能力,因此可以使用放大来组织攻击。 也就是说,攻击者扫描 Internet 并发现易受攻击或配置不正确的服务器,例如,这些服务器在响应一个 SYN 数据包时会响应三个 SYN-ACK。 通过从目标服务器的地址欺骗源地址,可以将单个数据包的功率增加三倍,并将流量重定向到受害者。

DDoS 救援:我们如何进行压力和负载测试

扩增的问题在于它们难以检测。 最近的例子包括易受攻击的 memcached 的耸人听闻的案例。 另外,现在有很多物联网设备,IP摄像机,它们也大多是默认配置的,而且默认配置不正确,这就是为什么攻击者最常通过此类设备进行攻击。

DDoS 救援:我们如何进行压力和负载测试

困难的 SYN 泛洪

从开发人员的角度来看,SYN 洪水可能是最有趣的攻击类型。 问题是系统管理员经常使用 IP 封锁来进行保护。 此外,IP 封锁不仅影响使用脚本操作的系统管理员,而且不幸的是,还影响一些花费大量资金购买的安全系统。
这种方法可能会变成一场灾难,因为如果攻击者替换 IP 地址,该公司将封锁自己的子网。 当防火墙阻止自己的集群时,输出将导致外部交互失败,并且资源将失败。
而且,封锁自己的网络并不困难。 如果客户的办公室有 Wi-Fi 网络,或者使用各种监控系统测量资源的性能,那么我们会采用该监控系统的 IP 地址或客户办公室的 Wi-Fi 并将其用作源。 最后,资源看似可用,但目标IP地址被阻止。 因此,公司新产品展示的HighLoad会议的Wi-Fi网络可能会被封锁,这会带来一定的商业和经济成本。
在测试过程中,我们不能通过 memcached 对任何外部资源使用放大,因为有协议仅将流量发送到允许的 IP 地址。 因此,我们通过 SYN 和 SYN-ACK 进行放大,当系统用两个或三个 SYN-ACK 响应发送一个 SYN 时,在输出处攻击会放大两到三倍。

工具

我们用于 L7 工作负载的主要工具之一是 Yandex-tank。 特别是,模型被用作枪,此外还有几个用于生成弹药筒和分析结果的脚本。
tcpdump用于分析网络流量,Nmap用于分析服务器。 为了在 L3 和 4 级别创建负载,使用了 OpenSSL 和我们自己的 DPDK 库的一些魔法。 DPDK 是 Intel 的一个库,允许您绕过 Linux 堆栈使用网络接口,从而提高效率。 当然,我们不仅在 L3&4 级别使用 DPDK,还在 L7 级别使用 DPDK,因为它允许我们创建非常高的负载流,在一台机器每秒数百万个请求的范围内。
我们还使用为特定测试编写的某些流量生成器和特殊工具。 如果我们回忆一下 SSH 下的漏洞,那么上述设置就无法被利用。 如果我们攻击邮件协议,我们会采用邮件实用程序或简单地在其上编写脚本。

发现

作为结论我想说:

  • 除了经典的负载测试之外,还需要进行压力测试。 我们有一个真实的例子,其中合作伙伴的分包商仅执行负载测试。 表明该资源能够承受正常负载。 但随后出现了异常负载,站点访问者开始以稍微不同的方式使用资源,结果分包商停了下来。 因此,即使您已经受到 DDoS 攻击的保护,也值得寻找漏洞。
  • 有必要将系统的某些部分与其他部分隔离。 如果您有搜索,则需要将其移动到单独的机器上,也就是说,甚至不能移动到 Docker 上。 因为如果搜索或授权失败,至少有些东西会继续工作。 对于在线商店,用户将继续在目录中查找产品、从聚合器中查找产品、在已授权的情况下购买或通过 OAuth2 授权。
  • 不要忽视各种云服务。
  • 使用CDN不仅可以优化网络延迟,还可以作为防止通道耗尽和简单涌入静态流量的攻击的一种手段。
  • 有必要使用专门的保护服务。 您无法在通道级别保护自己免受 L3&4 攻击,因为您很可能根本没有足够的通道。 您也不太可能抵御 L7 攻击,因为它们可能非常大。 另外,寻找小型攻击仍然是特殊服务、特殊算法的特权。
  • 定期更新。 这不仅适用于内核,也适用于 SSH 守护进程,特别是当它们向外部开放时。 原则上,一切都需要更新,因为您不太可能自己跟踪某些漏洞。

来源: habr.com

添加评论