TCP洪水攻击(SYN Flood)的诊断和处理

1. SYN Flood介绍

   前段时间网站被攻击屡次,其中最猛烈的就是TCP洪水攻击,即SYN Flood。html

   SYN Flood是当前最流行的DoS(拒绝服务攻击)与DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP链接请求,经常使用假冒的IP或IP号段发来海量的请求链接的第一个握手包(SYN包),被攻击服务器回应第二个握手包(SYN+ACK包),由于对方是假冒IP,对方永远收不到包且不会回应第三个握手包。致使被攻击服务器保持大量SYN_RECV状态的“半链接”,而且会重试默认5次回应第二个握手包,塞满TCP等待链接队列,资源耗尽(CPU满负荷或内存不足),让正常的业务请求链接不进来。linux

   详细的原理,网上有不少介绍,应对办法也不少,但大部分没什么效果,这里介绍咱们是如何诊断和应对的。web

2. 诊断

   咱们看到业务曲线大跌时,检查机器和DNS,发现只是对外的web机响应慢、CPU负载高、ssh登录慢甚至有些机器登录不上,检查系统syslog:后端

   # tail -f /var/log/messages数组

   Apr 18 11:21:56 web5 kernel: possible SYN flooding on port 80. Sending cookies.bash

   检查链接数增多,而且SYN_RECV 链接特别多:服务器

   # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'cookie

   TIME_WAIT 16855网络

   CLOSE_WAIT 21并发

   SYN_SENT 99

   FIN_WAIT1 229

   FIN_WAIT2 113

   ESTABLISHED 8358

   SYN_RECV 48965

   CLOSING 3

   LAST_ACK 313

   根据经验,正常时检查链接数以下:

   # netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

   TIME_WAIT 42349

   CLOSE_WAIT 1

   SYN_SENT 4

   FIN_WAIT1 298

   FIN_WAIT2 33

   ESTABLISHED 12775

   SYN_RECV 259

   CLOSING 6

   LAST_ACK 432

   以上就是TCP洪水攻击的两大特征。执行netstat -na>指定文件,保留罪证。

3. 应急处理

   根据netstat查看到的对方IP特征:

   # netstat -na |grep SYN_RECV|more

   利用iptables临时封掉最大嫌疑攻击的IP或IP号段,例如对方假冒173.*.*.*号段来攻击,短时间禁用173.*.*.*这个大号段(要确认当心不要封掉本身的本地IP了!)

   # iptables -A INPUT -s  173.0.0.0/8  -p tcp  -dport 80 -j DROP

   再分析刚才保留的罪证,分析业务,用iptables解封正常173.*.*.*号段内正常的ip和子网段。这样应急处理很容易误伤,甚至可能由于封错了致使ssh登录不了服务器,并非理想方式。

4. 使用F5挡攻击    

   应急处理毕竟太被动,由于本机房的F5比较空闲,运维利用F5来挡攻击,采用方式:让客户端先和F5三次握手,链接创建以后F5才转发到后端业务服务器。后来被攻击时F5上看到的现象:

   1. 链接数比平时多了500万,攻击中止后恢复。

   2. 修改F5上咱们业务的VS模式后,F5的CPU消耗比平时多7%,攻击中止后恢复。

   3. 用F5挡效果明显,后来因攻击无效后,用户不多来攻击了,毕竟攻击也是有成本的。

5. 调整系统参数挡攻击    

   没有F5这种高级且昂贵的设备怎么办?我测试过如下参数组合能明显减少影响,准备之后不用F5抗攻击。

   第一个参数tcp_synack_retries = 0是关键,表示回应第二个握手包(SYN+ACK包)给客户端IP后,若是收不到第三次握手包(ACK包)后,不进行重试,加快回收“半链接”,不要耗光资源。

   不修改这个参数,模拟攻击,10秒后被攻击的80端口即没法服务,机器难以ssh登陆; 用命令netstat -na |grep SYN_RECV检测“半链接”hold住180秒;

   修改这个参数为0,再模拟攻击,持续10分钟后被攻击的80端口均可以服务,响应稍慢些而已,只是ssh有时也登陆不上;检测“半链接”只hold住3秒即释放掉。

   修改这个参数为0的反作用:网络情况不好时,若是对方没收到第二个握手包,可能链接服务器失败,但对于通常网站,用户刷新一次页面便可。这些能够在高峰期或网络情况很差时tcpdump抓包验证下。

   根据之前的抓包经验,这种状况不多,但为了保险起见,能够只在被tcp洪水攻击时临时启用这个参数。

   tcp_synack_retries默认为5,表示重发5次,每次等待30~40秒,即“半链接”默认hold住大约180秒。详细解释:

The tcp_synack_retries setting tells the kernel how many times to retransmit the SYN,ACK reply to

   an SYN request. In other words, this tells the system how many times to try to establish a passive

   TCP connection that was started by another host.

   This variable takes an integer value, but should under no circumstances be larger than 255 for the

   same reasons as for the tcp_syn_retries variable. Each retransmission will take aproximately 30-40

   seconds. The default value of the tcp_synack_retries variable is 5, and hence the default timeout

   of passive TCP connections is aproximately 180 seconds.

   之因此能够把tcp_synack_retries改成0,由于客户端还有tcp_syn_retries参数,默认是5,即便服务器端没有重发SYN+ACK包,客户端也会重发SYN握手包。详细解释:

The tcp_syn_retries variable tells the kernel how many times to try to retransmit the initial SYN

   packet for an active TCP connection attempt.

   This variable takes an integer value, but should not be set higher than 255 since each

   retransmission will consume huge amounts of time as well as some amounts of bandwidth. Each

   connection retransmission takes aproximately 30-40 seconds. The default setting is 5, which

   would lead to an aproximate of 180 seconds delay before the connection times out.

   第二个参数net.ipv4.tcp_max_syn_backlog = 200000也重要,具体多少数值受限于内存。

   如下配置,第一段参数是最重要的,第二段参数是辅助的,其他参数是其余做用的:

   # vi /etc/sysctl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#最关键参数,默认为5,修改成0 表示不要重发
net.ipv4.tcp_synack_retries = 0
#半链接队列长度
net.ipv4.tcp_max_syn_backlog = 200000
 
#系统容许的文件句柄的最大数目,由于链接须要占用文件句柄
fs.file-max = 819200
#用来应对突发的大并发connect 请求
net.core.somaxconn = 65536
#最大的TCP 数据接收缓冲(字节)
net.core.rmem_max = 1024123000
 
#最大的TCP 数据发送缓冲(字节)
net.core.wmem_max = 16777216
#网络设备接收数据包的速率比内核处理这些包的速率快时,容许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 165536
#本机主动链接其余机器时的端口分配范围
net.ipv4.ip_local_port_range = 10000 65535
 
# ……省略其它……

   使配置生效:

   # sysctl -p

   注意,如下参数面对外网时,不要打开。由于反作用很明显,具体缘由请google,若是已打开请显式改成0,而后执行sysctl -p关闭。由于通过试验,大量TIME_WAIT状态的链接对系统没太大影响:

1
2
3
4
5
6
7
8
#当出现 半链接 队列溢出时向对方发送syncookies,调大 半链接 队列后不必
net.ipv4.tcp_syncookies = 0
#TIME_WAIT状态的链接重用功能
net.ipv4.tcp_tw_reuse = 0
#时间戳选项,与前面net.ipv4.tcp_tw_reuse参数配合
net.ipv4.tcp_timestamps = 0
#TIME_WAIT状态的链接回收功能
net.ipv4.tcp_tw_recycle = 0

   为了处理大量链接,还需改大另外一个参数:

   # vi /etc/security/limits.conf

   在底下添加一行表示容许每一个用户都最大可打开409600个文件句柄(包括链接):

   *                -       nofile          409600

6. 参考资料    

   文件句柄不要超过系统限制/usr/include/linux/fs.h,相关连接:http://blog.yufeng.info/archives/1380

   #define NR_OPEN (1024*1024)     /* Absolute upper limit on fd num */

   内核参数详细解释:http://www.frozentux.net/ipsysctl-tutorial/chunkyhtml/tcpvariables.html

   

7. 结束语    

   TCP洪水攻击还没完美解决方案,但愿本文对您有所帮助,让您快速了解。

相关文章
相关标签/搜索