从攻击的原理上来看,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 攻击带来的性能下降问题?