起因
公网服务器 access log 每天几千条扫描尝试:SSH 暴力破解、WordPress 路径
扫描、各种 CVE 探测。一台 VPS 偶尔被低强度 SYN flood 打到延迟飙升。
fail2ban + ufw 能挡掉大部分,但更基础的内核层防护让攻击者连 TCP 握手
都建立不了,更省 CPU。
解决方案:三道防线
1. SYN cookies 启用(内核级 SYN flood 防护)
# 临时
sudo sysctl -w net.ipv4.tcp_syncookies=1
sudo sysctl -w net.ipv4.tcp_max_syn_backlog=8192
sudo sysctl -w net.ipv4.tcp_synack_retries=2
# 持久 /etc/sysctl.d/99-syn-protect.conf
cat <<EOF | sudo tee /etc/sysctl.d/99-syn-protect.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_fin_timeout = 15
net.core.somaxconn = 4096
net.ipv4.tcp_tw_reuse = 1
EOF
sudo sysctl --system
tcp_syncookies=1 让内核在 SYN backlog 满时改用 cookie 验证客户端,
不分配真实 socket,让 SYN flood 失效(攻击者要回 ACK 才占资源)。
2. iptables/nftables 限速 SYN
iptables 版(老但通用):
# 每秒最多 25 个新连接,超过的丢弃
sudo iptables -N SYN_FLOOD
sudo iptables -A INPUT -p tcp --syn -j SYN_FLOOD
sudo iptables -A SYN_FLOOD -m limit --limit 25/s --limit-burst 50 -j RETURN
sudo iptables -A SYN_FLOOD -j LOG --log-prefix "SYN_FLOOD: "
sudo iptables -A SYN_FLOOD -j DROP
# 持久化
sudo apt install iptables-persistent
sudo netfilter-persistent save
nftables 版(推荐,新机器都用这个):
table inet filter {
# 限速:每秒 25 个新 SYN,突发 50
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif lo accept
ip protocol icmp accept
meta nfproto ipv6 icmpv6 accept
# 新 SSH 连接限速
tcp dport 22 ct state new \
limit rate over 6/minute \
counter drop
tcp dport 22 accept
# HTTP/S 限速 SYN(防 layer-4 DDoS)
tcp dport { 80, 443 } ct state new \
limit rate over 50/second burst 100 packets \
counter drop
tcp dport { 80, 443 } accept
# 默认 log + drop
limit rate 5/minute log prefix "nft drop: "
counter drop
}
}
3. 用 ipset / nft set 屏蔽已知恶意 IP 段
sudo apt install ipset
# 创建 set
sudo ipset create blacklist hash:net
# 加 IP 段(来自公开威胁情报源)
curl -s https://lists.blocklist.de/lists/ssh.txt \
| xargs -I {} sudo ipset add blacklist {} 2>/dev/null
# 接到 iptables
sudo iptables -I INPUT -m set --match-set blacklist src -j DROP
或 nftables 的 set(更优雅):
table inet filter {
set blacklist {
type ipv4_addr
flags interval
elements = {
45.95.169.0/24,
193.32.162.0/24,
# ... 几千条
}
}
chain input {
ip saddr @blacklist drop
# ... 其它规则
}
}
更新 set 用 nft add element,无需重启。
4. conntrack 调优
# /etc/sysctl.d/99-conntrack.conf
# 默认 65536 在高并发被吃满("nf_conntrack: table full" log)
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 7200
net.netfilter.nf_conntrack_buckets = 262144
观察当前用量:
sudo sysctl net.netfilter.nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
接近 max 时 conntrack 表满 → 新连接被 drop。
5. 校验 / 监控
# 看 SYN 状态
ss -tan state syn-recv | wc -l
ss -tan state established | wc -l
# 看 conntrack 表
sudo conntrack -L | wc -l
sudo conntrack -S # 统计
# iptables / nft 命中数
sudo nft list ruleset | grep counter
实时看被 drop 的:
sudo journalctl -k -f | grep -E 'nft drop|SYN_FLOOD'
效果
- 之前一次 SYN flood 把 CPU 打到 60% → 现在内核层 cookie + 限速消化,
CPU 几乎不动 - SSH brute force 日志从每天 5000+ 条 → < 50 条(被 nft limit 提前丢)
- 已知恶意 IP 段(blocklist.de 等)直接 drop,访问日志几乎清净
- nginx 不再被无效请求打扰,正常用户体验改善
性能成本
- iptables/nftables 处理一个包 nanosecond 级
- conntrack 每连接 ~300 bytes,1M 连接 ~300 MB(VPS 4GB+ 没压力)
- 内核 SYN cookie 极少 CPU
公网服务器开这些防护是"几乎免费的保险"。
与 Cloudflare / DDoS 服务对比
应用 / VPS 自己防只能挡到 L3-L4 中等流量(< 1 Gbps)。
大规模 DDoS(10 Gbps+)流量已经把上游带宽打满,再防火墙也无济于事。
正经防 DDoS 要前置 Cloudflare / AWS Shield 等大网络服务商,
利用它们的全球抗 D 能力。
但这些没必要 24x7 开(成本);做好本地防护 + 紧急时切到 Cloudflare
"under attack" 模式是合理 trade-off。
踩过的坑
-
限速规则放错位置:
limit rate必须在accept之前。我曾把
accept 写前面 → 所有连接都 accept,limit 形同虚设。 -
ct state new漏写:限速规则没ct state new就把 established
连接的每个包都算 → 正常流量也被限速。 -
blacklist 来源选择:随便加几万条 IP 进 ipset 可能误封 CDN /
公有云 IP(共享网段)。用 abuseipdb / blocklist.de 这种带置信度
评分的源,confidence > 90 才加。 -
iptables vs nftables 共存:新 Debian/Ubuntu 用
iptables-nft
兼容层,老 iptables 命令实际写 nftables。混改 iptables 命令 + nft
命令导致规则错乱。统一用 nft。 -
重启后规则丢:iptables 改了忘
netfilter-persistent save;
nftables 改了忘写/etc/nftables.conf。养成"改完测试 →立刻
持久化"习惯。
登录后参与评论。