用 iptables / nftables 抗 SYN flood + 限速暴力扫描

起因

公网服务器 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。

踩过的坑

  1. 限速规则放错位置limit rate 必须在 accept 之前。我曾把
    accept 写前面 → 所有连接都 accept,limit 形同虚设。

  2. ct state new 漏写:限速规则没 ct state new 就把 established
    连接的每个包都算 → 正常流量也被限速。

  3. blacklist 来源选择:随便加几万条 IP 进 ipset 可能误封 CDN /
    公有云 IP(共享网段)。用 abuseipdb / blocklist.de 这种带置信度
    评分的源,confidence > 90 才加。

  4. iptables vs nftables 共存:新 Debian/Ubuntu 用 iptables-nft
    兼容层,老 iptables 命令实际写 nftables。混改 iptables 命令 + nft
    命令导致规则错乱。统一用 nft。

  5. 重启后规则丢:iptables 改了忘 netfilter-persistent save
    nftables 改了忘写 /etc/nftables.conf。养成"改完测试 →立刻
    持久化"习惯。

精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。