VPS抗DDoS千万别自己乱上iptables:五个坑让我差点把高防回源也封了
写在前边:为什么你越“防”越容易被打崩
很多新手给VPS上防御DDoS,第一反应是GitHub搜现成的iptables脚本,或者把网上流传的“内核抗DDoS参数”一顿粘贴。但真实攻击一来,要么CPU被打满、要么新连接全部被丢、要么高防回源直接被自己防火墙干掉。这篇不聊理论,只讲我在多个VPS上踩过的具体坑。
坑一:几千条DROP规则是给网卡上刑
被秒封IP后,新手喜欢把攻击IP一条条追加进去:
iptables -A INPUT -s 1.2.3.4 -j DROP
iptables -A INPUT -s 5.6.7.8 -j DROP
...
几千条不命中链规则后,每个新包都要线性扫一遍,CPU软中断直接飙升。正确是用ipset做一个集合,然后用一条规则引用:
ipset create blacklist hash:ip timeout 3600
iptables -I INPUT -m set --match-set blacklist src -j DROP
封IP就变成往集合里加:
ipset add blacklist 1.2.3.4
ipset del blacklist 1.2.3.4
无论封多少IP,防火墙匹配代价都是O(1)。注意:不要用-m recent频繁更新IP集合,攻击流量大时recent锁竞争会拖死整个收包路径。
坑二:把syncookies当万能神药,但忘了SYNPROXY
遇到SYN Flood,常见调参是:
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
syncookies确实能保住握手,但高并发下内核态计算cookie非常费CPU。在KVM VPS上,更狠的是用内核自带的SYNPROXY,把SYN包放在raw表直接处理:
modprobe nf_conntrack_syncookies
iptables -t raw -A PREROUTING -p tcp --dport 80 --tcp-flags SYN SYN -j CT --notrack
iptables -A INPUT -p tcp --dport 80 -m state --state INVALID -j DROP
iptables -A INPUT -p tcp --dport 80 -m state --state UNTRACKED -j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460
注意:部分OpenVZ/LXC VPS不支持SYNPROXY,因为容器没有完整Netfilter权限。买了便宜OVZ的小白别折腾,直接上高防更靠谱。
坑三:高防回源IP被自己“防御”误杀
买了高防IP后,源站VPS必须允许高防回源流量。很多新手只放行了高防IP的80端口,却忘了一条:高防回源的连接是从高防IP建立的,但SYN包的源IP有可能不是你想象的那个“固定IP”。如果高防IP段有多个出口,你只白名单单个IP,大概率误杀。更稳的做法是:先放行所有已建立的连接,再放行所有TCP 80端口,其他端口全部关闭:
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j DROP
别把--src设成具体的高防IP。我当年就是只放行了一个高防出口IP,攻击流量一压,高防切换线路后回源IP变了,VPS直接失联。
坑四:nf_conntrack打满,什么规则都白搭
DDoS攻击不一定是大流量,也可能是连接耗尽。默认VPS的conntrack表最大只有65536,每条连接表项占内存,攻击瞬间填充全表后,新连接包括高防回源全部被丢。先看使用率:
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
如果count接近max,果断调大,但别盲目。一个连接大概占350字节内存,2GB内存的VPS可以设到10万,4GB设到20万:
sysctl -w net.netfilter.nf_conntrack_max=200000
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=120
同时把无效连接直接丢:
iptables -A INPUT -m state --state INVALID -j DROP
注意:如果VPS用的是nftables,则先加载nf_conntrack模块,否则state匹配是空的。
坑五:慢速应用层攻击 —— Nginx默认配置都能被打跪
很多新手只防“大流量”,却不防Slowloris这类慢速攻击。攻击者建立连接后慢慢发HTTP头,Nginx默认等待超时60秒,几百个连接就能占满worker。直接在Nginx配置里加:
# /etc/nginx/nginx.conf http段
client_header_timeout 10s;
client_body_timeout 10s;
keepalive_timeout 5s 5s;
send_timeout 5s;
# 限制每个IP的并发连接数
limit_conn_zone $binary_remote_addr zone=conn_perip:10m;
limit_conn conn_perip 20;
# 限制请求频率
limit_req_zone $binary_remote_addr zone=req_perip:10m rate=10r/s;
limit_req zone=req_perip burst=20 nodelay;
这里特别提醒:不要用limit_conn去限制总连接数,不然高防回源的长连接也会被误杀。只按$binary_remote_addr限制单个客户端即可。
最后一课:确认你的VPS虚拟化类型再动手
SYNPROXY、nf_conntrack_max调优、ipset的timeout特性,都依赖完整内核权限。KVM虚拟化的VPS随便改,OpenVZ的VPS改不了内核参数,甚至iptables -m set都可能是阉割的。新手买VPS练手防御,优先选KVM架构。我用过的轻云互联洛杉矶VPS就是KVM,而且自带入方向基础清洗能力,至少让我不用担心流量打爆母机。但千万别因此以为“高防”一劳永逸——回源后仍需自己做源站防护。
最后补一刀:所有iptables规则改动,先用iptables-save > /root/firewall.rules备份。别问我怎么知道的。