在我的上一篇文章谈到了如何使用 tcpdump
和 wireshark
,并带您了解了几个用例。今天我们来看看另一个常见的问题,如何缓解 DDoS(分布式拒绝服务)导致的性能下降。
DDoS 的前身是 DoS(Denial of Service),即拒绝服务攻击,是指利用大量合理请求占用过多目标资源,使目标服务无法响应正常的请求.
DDoS(Distributed Denial of Service)采用基于 DoS 的分布式架构,利用多台主机同时攻击目标主机。这样,即使目标服务部署了网络防御设备,仍然无法应对大量的网络请求。
从攻击原理来看,DDoS 可分为以下几种。
无论哪种类型的 DDoS,危害都是巨大的。那么,如何发现系统遭受了 DDoS 攻击,如何应对这种攻击呢?让我带您了解一个现实生活中的用例。
您需要遵循:
3 台 Linux 主机:应用程序、攻击者、客户端
预安装 docker
、sar
、hping3
、tcpdump
、curl
。
让我们在应用主机上启动一个简单的 nginx
服务:
[root@app ~]# docker run -itd --name=nginx --network=host nginx
a8b3685d5eef0ffa2dead081b88d50d777db04bedbdb77ba886ca89b4bb690d2
[root@app ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a8b3685d5eef nginx "/docker-entrypoint.…" 24 seconds ago Up 21 seconds nginx
然后,在客户端主机中,使用 curl
访问 Nginx 正在监听的端口,并确认 Nginx 已经正常启动:
[root@client ~]# curl -s -w 'Http code: %{http_code}
Total time:%{time_total}s
' -o /dev/null http://172.31.88.139
Http code: 200
Total time:0.002437s
从这里可以看出,正常情况下,我们访问 Nginx 只需要 2ms(0.002s)。
现在,让我们从攻击者主机那里运行 hping3
命令来模拟 Dos 攻击:
# -S means set syn,-p means port 80
# -i u10 send a packet frame every 10 m-seconds
$ hping3 -S -p 80 -i u10 --flood 192.168.0.30
HPING 172.31.88.139 (eth0 172.31.88.139): S set, 40 headers + 0 data bytes
hping in flood mode, no replies will be shown
现在让我们回到客户端主机,再次尝试 curl
命令:
[root@client ~]# curl -s -w 'Http code: %{http_code}
Total time:%{time_total}s
' -o /dev/null http://172.31.88.139
Http code: 000
Total time:10.001s
curl: (28) Connection timed out after 10000 milliseconds
这次普通客户端的连接超时,其并没有收到 Nginx 服务的响应。
这里发生了什么事呢?让我们回到主机应用程序,并检查当前的网络状态:
[root@app ~]# sar -n DEV 1
0849 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
0850 docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0850 eth0 22274.00 629.00 1174.64 37.78 0.00 0.00 0.00 0.02
0850 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
从这次 sar
的输出可以看出,网络接收到的 PPS 已经达到 2 万多,但是 BPS 只有 1174kB。因此,可以计算每个包的大小只有 54B()。
包大小不算大,但这是个什么样的包呢?让我们使用 tcpdump
来捕获:
[root@app ~]# tcpdump -i eth0 -n tcp port 80
0948.287047 IP 172.31.82.28.27095 > 172.31.88.139: Flags [S], seq 1288268370, win 512, length 0
0948.287050 IP 172.31.82.28.27131 > 172.31.88.139: Flags [S], seq 2084255254, win 512, length 0
0948.287052 IP 172.31.82.28.27116 > 172.31.88.139: Flags [S], seq 677393791, win 512, length 0
0948.287055 IP 172.31.82.28.27141 > 172.31.88.139: Flags [S], seq 1276451587, win 512, length 0
0948.287068 IP 172.31.82.28.27154 > 172.31.88.139: Flags [S], seq 1851495339, win 512, length 0
...
在该输出中,Flags [S]
表示这是一个 SYN 数据包。而大量的 SYN 数据包表明这是一次 SYN Flood 攻击。如果我们用 wireshark
来观察,可以更加直观地看到 SYN Flood 的过程:
事实上,SYN Flood 是互联网上最经典的 DDoS 攻击。从上图也可以看出它的原理:
这种等待状态的 TCP 连接通常也称为半开连接(Half-Open Connection)。由于连接表(Connection Table)的大小是有限的,而大量的半开连接会导致连接表快速填满,从而无法建立新的 TCP 连接。
从下面的 TCP 状态图可以看到,此时服务器端的 TCP 连接会处于 SYN_RECEIVED
状态:
我们可以使用 netstat
来查看所有连接的状态,但需要注意的是 SYN_REVEIVED
的状态通常缩写为 SYN_RECV
。
[root@app ~]# netstat -n -p | grep SYN_REC
tcp 0 0 172.31.88.139:80 172.31.82.28:12503 SYN_RECV -
tcp 0 0 172.31.88.139:80 172.31.82.28:13502 SYN_RECV -
tcp 0 0 172.31.88.139:80 172.31.82.28:15256 SYN_RECV -
tcp 0 0 172.31.88.139:80 172.31.82.28:18117 SYN_RECV -
...
从结果中可以发现,存在大量的 SYN_RECV
状态的连接,源 IP 地址为 172.31.82.28
。现在,让我们统计一下正处于 SYN_RECV
状态的连接数:
[root@app ~]# netstat -n -p | grep SYN_REC | wc -l
193
找出源 IP 后,只需丢弃相关数据包即可解决 SYN 攻击的问题。此时,iptables
可以帮你完成这个任务:(注意:Serban 在评论中建议“在这种情况下,DROP
比可能 REJECT
更好”)
[root@app ~]# iptables -I INPUT -s 172.31.82.28 -p tcp -j REJECT
执行上述命令后,让我们再次从客户端主机尝试 curl
:
$ curl -w 'Http code: %{http_code}
Total time:%{time_total}s
'-o /dev/null--connect-timeout 10 http://172.31.88.139
Http code: 200
Total time:1.572171s
但一般来说,SYN Flood 攻击中的源 IP 是不固定的(例如,您可以通过将 --rand-source
选项添加到 hping3
命令来随机化源 IP)。此时,刚才的方法并不适用。
幸运的是,我们还有许多其他方法可以达到类似的目的。例如,我们可以通过两种方式限制同步数据包的速率:
# Limit the number of syn concurrency to 1 per second
$ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT
#Limit the number of newly established connections for a single IP in 60 seconds to 10
$ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT
到目前为止,我们已经初步限制了 SYN Flood 攻击。但这还不够,因为我们的案例只是单一的攻击源。
如果多台机器同时发送 SYN Flood,则该方法可能直接失效。因为您可能无法通过 SSH 连接到机器(SSH 也是基于 TCP 的),更不用说执行上面的那些排查命令了。
为了缓解多台机器的 SYN Flood 攻击,我们可以将半开连接容量从默认的 256 增加到 1024:
$ sysctl net.ipv4.tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 256
$ sysctl -w net.ipv4.tcp_max_syn_backlog=1024net.ipv4.tcp_max_syn_backlog = 1024
另外,每当连接状态为 SYN_RECV 的连接时,如果连接失败,内核会自动重试,默认重试次数为 5 次。您可以通过执行以下命令将其减少到 1 次:
$ sysctl -w net.ipv4.tcp_synack_retries=1
net.ipv4.tcp_synack_retries = 1
此外,TCP SYN Cookies 也是一种特殊的防御 SYN Flood 攻击的机制。SYN Cookies 根据连接信息(包括源地址、源端口、目的地址、目的端口等)和加密种子(如系统启动时间)计算哈希值(SHA1)。该哈希值称为 cookie。启用 SYN Cookies 后,无需再保持半开连接状态,同时半开连接的数量也将没有限制。
$ sysctl -w net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syncookies = 1
需要注意的是,上面 sysctl
命令所修改的配置是临时的,重启后将会丢失。您可以通过将它们添加到 /etc/sysctl.conf
文件中使其持久化。例如:
$ cat /etc/sysctl.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_max_syn_backlog = 1024
$ sysctl -p
今天,我们谈到了在分布式拒绝服务 (DDoS) 情况下的缓解措施。DDoS 利用大量伪造请求,使目标服务消耗大量资源来处理这些无效的请求,进而无法正常响应正常用户请求。
由于 DDoS 分布的流量大和难以追踪等特点,目前没有办法完全防御 DDoS 带来的问题,因此只能缓解其造成的影响。
原文标题:如何在 Linux 上模拟和缓解 DDoS 攻击
文章出处:【微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !