「ddos」-

  CREATED BY JENKINSBOT

从攻击的原理上来看,DDoS 可以分为下面几种类型:
1)耗尽带宽。无论是服务器还是路由器、交换机等网络设备,带宽都有固定的上限。带宽耗尽后,就会发生网络拥堵,从而无法传输其他正常的网络报文
2)耗尽操作系统的资源。网络服务的正常运行,都需要一定的系统资源,像是 CPU、内存等物理资源,以及连接表等软件资源。一旦资源耗尽,系统就不能处理其他正常的网络连接
3)消耗应用程序的运行资源。应用程序的运行,通常还需要跟其他的资源或系统交互。如果应用程序一直忙于处理无效请求,也会导致正常请求的处理变慢,甚至得不到响应

模拟 DDOS 攻击

# docker run -itd --name=nginx --network=host nginx

// 测试当前访问速度

# curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.0.30/
...
Http code: 200
Total time:0.002s

// 模拟 DDOS 攻击

# hping3 -S -p 80 -i u10 192.168.0.30

// -S 参数表示设置TCP协议的SYN(同步序列号),-p表示目的端口为80
// -i u10 表示每隔10微秒发送一个网络帧

// 测试当前访问速度

# curl -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null --connect-timeout 10 http://192.168.0.30
...
Http code: 000
Total time:10.001s
curl: (28) Connection timed out after 10000 milliseconds

// --connect-timeout表示连接超时时间

观察网络流量

# sar -n DEV 1
08:55:49        IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s   %ifutil
08:55:50      docker0      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00
08:55:50         eth0  22274.00    629.00   1174.64     37.78      0.00      0.00      0.00      0.02
08:55:50           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00      0.00

// 网络接收的 PPS 已经达到了 20000 多,但是 BPS 却只有 1174 kB,这样每个包的大小就只有 54B(1174*1024/22274=54)

// 接下来使用 tcpdump 抓包排查

# tcpdump -i eth0 -n tcp port 80
09:15:48.287047 IP 192.168.0.2.27095 > 192.168.0.30: Flags [S], seq 1288268370, win 512, length 0
09:15:48.287050 IP 192.168.0.2.27131 > 192.168.0.30: Flags [S], seq 2084255254, win 512, length 0
09:15:48.287052 IP 192.168.0.2.27116 > 192.168.0.30: Flags [S], seq 677393791, win 512, length 0
09:15:48.287055 IP 192.168.0.2.27141 > 192.168.0.30: Flags [S], seq 1276451587, win 512, length 0
09:15:48.287068 IP 192.168.0.2.27154 > 192.168.0.30: Flags [S], seq 1851495339, win 512, length 0
...

// -i eth0 只抓取eth0网卡,-n 不解析协议名和主机名
// tcp port 80 表示只抓取 tcp 协议并且端口号为 80 的网络帧

// 大量的 SYN 包表明,这是一个 SYN Flood 攻击

SYN Flood

SYN Flood 的原理:
1)客户端构造大量的 SYN 包,请求建立 TCP 连接
2)服务器收到包后,会向源 IP 发送 SYN+ACK 报文,并等待三次握手的最后一次 ACK 报文,
3)客户端不响应 ACK 报文,使客户端直到超时

查看半开连接(SYN_RECEIVED)

# netstat -n -p | grep SYN_REC // -n 表示不解析名字,-p 表示显示连接所属进程
tcp        0      0 192.168.0.30:80          192.168.0.2:12503      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:13502      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:15256      SYN_RECV    -
tcp        0      0 192.168.0.30:80          192.168.0.2:18117      SYN_RECV    -
...

// 统计半开连接数量
# netstat -n -p | grep SYN_REC | wc -l
193

解决 SYN 攻击

方法一、屏蔽地址

# iptables -I INPUT -s 192.168.0.2 -p tcp -j REJECT

方法二、限制频率

// 限制syn并发数为每秒1次

# iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT

// 限制单个IP在60秒新建立的连接数为10

# iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT

方法三、优化 TCP 参数

调整半开连接的数量,缓解针对业务的攻击,防止半开连接占满而无法 SSH 连接主机:

# sysctl -w net.ipv4.tcp_max_syn_backlog=1024

连接每个 SYN_RECV 时,如果失败的话,内核还会自动重试,并且默认的重试次数是 5 次。可以降低该参数:

# sysctl -w net.ipv4.tcp_synack_retries=1

开启 TCP SYN Cookies 功能:
1)基于连接信息以及一个加密种子,计算出一个哈希值(SHA1),这个哈希值称为 cookie 被用作序列号来应答 SYN+ACK 包,并释放连接状态
2)当客户端发送完三次握手的最后一次 ACK 后,服务器就会再次计算这个哈希值,确认是上次返回的 SYN+ACK 的返回包,才会进入 TCP 的连接状态

# sysctl -w net.ipv4.tcp_syncookies=1

防御 DDOS 攻击

更换网络方案

可以基于 XDP 或者 DPDK,构建 DDoS 方案,在内核网络协议栈前,或者跳过内核协议栈,来识别并丢弃 DDoS 报文,避免 DDoS 对系统其他资源的消耗。

购买流量清洗

对于流量型的 DDoS 来说,当服务器的带宽被耗尽后,在服务器内部处理就无能为力了。这时,只能在服务器外部的网络设备中,设法识别并阻断流量(当然前提是网络设备要能扛住流量攻击)。比如,购置专业的入侵检测和防御设备,配置流量清洗设备阻断恶意流量等。

应用程序优化

慢速的请求也会带来巨大的性能下降(这种情况称为慢速 DDoS)。比如很多针对应用程序的攻击,都会伪装成正常用户来请求资源。这种情况下,请求流量可能本身并不大,但响应流量却可能很大,并且应用程序内部也很可能要耗费大量资源处理。这时就需要应用程序考虑识别,并尽早拒绝掉这些恶意流量,比如合理利用缓存、增加 WAF(Web Application Firewall)、使用 CDN 等等。

参考文献

39 | 案例篇:怎么缓解 DDoS 攻击带来的性能下降问题?