Featured image of post 漫谈HTTP慢速攻击

漫谈HTTP慢速攻击

漏洞简介

DDos,全称Distributed Denial of Service,中文意思为“分布式拒绝服务”,就是利用大量合法的分布式计算机设备对目标服务器(网站等)发送请求,导致目标服务器CPU、内存、带宽等资源耗尽,从而导致正常用户无法访问目标服务器。通俗点讲就是利用网络节点资源,如:IDC服务器、个人PC、手机、智能设备、打印机、摄像头等对目标发起大量攻击请求,从而导致服务器拥塞,进而无法对外提供正常服务。

CC攻击(Challenge Collapsar),其前身名为Fatboy攻击。Collapsar(黑洞) 是绿盟科技的一款抗DDOS产品,在对抗拒绝服务攻击的领域内具有很高的影响力和口碑。因此,黑客们把攻击更名为Challenge Collapsar,表示要向黑洞发起挑战。

CC攻击是DDOS(分布式拒绝服务)的一种,是一种常见的网站攻击方法,攻击者通过代理服务器或者肉鸡向受害主机不停访问,造成服务器的内存或CPU等资源耗尽或带宽资源耗尽,直到网站无法访问。

因为CC攻击的访问流量来自成千上万,几十万,甚至数百万的电脑,手机,云主机等客户端。几乎和正常的用户访问没区别,这些攻击请求不具备明显的特征,很难和正常访问区分开来,防御难度也很大。尤其是利用肉鸡组成的僵尸网络发起攻击,动辄是数以万计的机器(其中很多机器可能都是普通用户使用的电脑手机等),这种攻击请求和正常用户请求非常相似,防御难度就更大了。

慢速攻击是CC攻击的变异品种

慢速攻击的基本原理如下:

对任何一个开放了HTTP访问的服务器HTTP服务器,先建立了一个连接(三次握手),指定一个比较大的content-length,然后以非常低的速度发包,比如1-10s发一个字节,然后维持住这个连接不断开。如果客户端持续建立这样的连接,那么服务器上可用的连接将一点一点被占满,从而导致拒绝服务。

只要Web服务器开放了Web服务,那么它就可以是一个靶子,HTTP协议在接收到request之前是不对请求内容作校验的,所以即使你的Web应用没有可用的form表单,这个攻击一样有效。

在客户端以单线程方式建立较大数量的无用连接,并保持持续发包的代价非常的低廉。实际实验中一台普通PC可以建立的连接在3000个以上。这对一台普通的Web server,将是致命的打击。更不用说结合肉鸡群做分布式DoS了。

对HTTP服务而言,会有几种基本攻击方式:

Slow header:Web应用在处理HTTP请求之前都要先接收完所有的HTTP头部,因为HTTP头部中包含了一些Web应用可能用到的重要的信息。攻击者利用这点,发起一个HTTP请求,一直不停的发送HTTP头部,消耗服务器的连接和内存资源。抓包数据可见,攻击客户端与服务器建立TCP连接后,每30秒才向服务器发送一个HTTP头部,而Web服务器再没接收到2个连续的\r\n时,会认为客户端没有发送完头部,而持续的等等客户端发送数据。

Slow body:攻击者发送一个HTTP POST请求,该请求的Content-Length头部值很大,使得Web服务器或代理认为客户端要发送很大的数据。服务器会保持连接准备接收数据,但攻击客户端每次只发送很少量的数据,使该连接一直保持存活,消耗服务器的连接和内存资源。抓包数据可见,攻击客户端与服务器建立TCP连接后,发送了完整的HTTP头部,POST方法带有较大的Content-Length,然后每10s发送一次随机的参数。服务器因为没有接收到相应Content-Length的body,而持续的等待客户端发送数据。

Slow read:客户端与服务器建立连接并发送了一个HTTP请求,客户端发送完整的请求给服务器端,然后一直保持这个连接,以很低的速度读取Response,比如很长一段时间客户端不读取任何数据,通过发送Zero Window到服务器,让服务器误以为客户端很忙,直到连接快超时前才读取一个字节,以消耗服务器的连接和内存资源。抓包数据可见,客户端把数据发给服务器后,服务器发送响应时,收到了客户端的ZeroWindow提示(表示自己没有缓冲区用于接收数据),服务器不得不持续的向客户端发出ZeroWindowProbe包,询问客户端是否可以接收数据。

漏洞复现

我们可以使用httpslowtest工具来测试程序是否存在此漏洞,这个工具目前提供了docker镜像:

1
$ docker pull shekyan/slowhttptest:latest

工具的参数如下:

-g 在测试完成后,以时间戳为名生成一个CVS和HTML文件的统计数据

-H SlowLoris模式

-B Slow POST模式

-R Range Header模式

-X Slow Read模式

-c number of connections 测试时建立的连接数

-d HTTP proxy host:port 为所有连接指定代理

-e HTTP proxy host:port 为探测连接指定代理

-i seconds 在slowrois和Slow POST模式中,指定发送数据间的间隔。

-l seconds 测试维持时间 -n seconds 在Slow Read模式下,指定每次操作的时间间隔。

-o file name 使用-g参数时,可以使用此参数指定输出文件名

-p seconds 指定等待时间来确认DoS攻击已经成功

-r connections per second 每秒连接个数

-s bytes 声明Content-Length header的值

-t HTTP verb 在请求时使用什么操作,默认GET

-u URL 指定目标url

-v level 日志等级(详细度)

-w bytes slow read模式中指定tcp窗口范围下限

-x bytes 在slowloris and Slow POST tests模式中,指定发送的最大数据长度

-y bytes slow read模式中指定tcp窗口范围上限

-z bytes 在每次的read()中,从buffer中读取数据量

Slow header攻击

1
$ docker run --rm shekyan/slowhttptest:latest -c 1000 -H -g -o my_header_stats -i 10 -r 200 -t GET -u <test_url> 24  -p 3

返回值大概如下:

1
2
3
4
5
6
7
8
slow HTTP test status on 55th second:

initializing:        0
pending:             8353
connected:           6558
error:               0
closed:              0
service available:   NO

service available: NO出现证明存在该问题。

Slow Body攻击

1
$ docker run --rm shekyan/slowhttptest:latest -c 3000 -B -g -o my_body_stats -i 110 -r 200 -s 8192 -t FAKEVERB -u <test_url> -x 10 -p 3

service available: NO出现证明存在该问题。

Slow read攻击

1
$ docker run --rm shekyan/slowhttptest:latest -c 8000 -X -r 200 -w 512 -y 1024 -n 5 -z 32 -k 3 -u <test_url> -p 3

service available: NO出现证明存在该问题。

应对

购买高防服务

可以通过配置DDoS高防IP服务,把自己的网站域名解析指向高防IP,并配置源站IP,所有公网流量都经过高防IP服务,在高防IP服务上进行清洗过滤后再将正常流量转发到源站IP,从而确保源站IP稳定访问。

另外,高防IP服务往往拥有超大带宽,一般的CC攻击几乎不可能耗尽高防IP服务的带宽资源,高防IP防御效果非常好,不过价格也比较贵。

页面静态化

如果可以,尽量将页面静态化,减少对后端服务的访问,静态页面可以充分利用客户端浏览器和反向代理的缓存能力。还可以上CDN,用CDN分担绝大部分的流量,可以大幅降低攻击流量到达后端服务的几率。

更改访问端口、避免IP泄漏

-

网关层限流

我们可以在网关层对IP限流,按分钟级和秒级维度限制接口访问次数,当访问次数超过指定阀值后对其他请求做抛弃处理,对访问量过大的IP,放进黑名单限制访问。将恶意请求的拦截前置到网关层处理,避免大量恶意请求打到后端服务,对服务造成巨大压力。

正确配置服务

nginx:

  • 调整http的连接参数

    • 关闭慢速连接 您可以关闭正在写入数据的连接,这可能意味着尝试尽可能保持连接打开(从而降低服务器接受新连接的能力)。该client_body_timeout指令控制NGINX在客户机体写入之间等待的时间,该client_header_timeout 指令控制NGINX在写入客户机标题之间等待的时间,这两个指令的默认值是60秒,本示例将NGINX配置为在来自客户端的写入或头文件之间等待不超过5秒钟:

      1
      2
      
      client_body_timeout 5s;
      client_header_timeout 5s;
      
    • keepalive_timeout 时间调短,默认是60秒,可以调整到5-10s;

      1
      
      keepalive_timeout 10s;
      
    • 在保证业务不受影响的前提下,调整client_max_body_size, client_body_buffer_size, client_header_buffer_size的值,必要时可以适当的增加;

    • 根据CPU和负载的大小,来配置worker_processes 和 worker_connections的值,公式是:max_clients = worker_processes * worker_connections。

  • 利用limit_req_zonelimit_req_conn来限制并发和连接

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 限制了同一ip1秒钟内最多可以请求8次
limit_req_zone $binary_remote_addr zone=one:10m rate=8r/s

# 声明同一ip的连接数限制为addr
limit_conn_zone $binary_remote_addr zone=addr:10m

# 同一ip的请求使用缓存,大小为5,并且不延迟
limit_req zone=one burst=5 nodelay

# 同一ip的连接数限制为3个
limit_conn addr 3