用 nftables 缓解 SYN flood 攻击 - V2EX
通过以下 Referral 链接购买 DigitalOcean 主机,你将可以帮助 V2EX 持续发展
DigitalOcean - SSD Cloud Servers
mdzz
V2EX    VPS

用 nftables 缓解 SYN flood 攻击

  •  
  •   mdzz Mar 19, 2023 2395 views
    This topic created in 1157 days ago, the information mentioned may be changed or developed.

    0x0: 初现端倪

    偶然一次登录到 VPS 上做日常维护, 用 ss -anpt 查看连接的时候发现大量连接处于 SYN-RECV 状态, 而且是同一 IP 大量连接到本机的 80 和 443 端口。 隔了一段时间后还是同样的情况,不过换了另一个 IP 。

    第一反应:“这不正常”。

    0x1: 肉鸡竟是我自己

    搜索后得知这是 SYN flood 的典型表现。

    攻击者向肉鸡发送大量伪造源地址的 SYN 包, 肉鸡收到 SYN 包后向伪造地址发送 SYN-ACK 包。 如果没有收到伪造地址的 ACK 包,则会重新发送 SYN-ACK 包。 重发机制使得攻击被放大了。 如下所示:

    A \ SYN \ B \ \ \ \ \SYN-ACK \ \ \ \ \ C 

    虽然对单一肉鸡来讲,流量和性能都没有很大的影响, 但对被攻击者来说就是另一种感受了。

    0x2: 尝试 Synproxy

    启用 synproxy 模块后,TCP 三次握手将由 synproxy 模块处理, 并在连接建立成功后再向上层抛出这三个包。 从而保护上层系统不受攻击。

    首先配置需要的 sysctl 选项

    net.netfilter.nf_conntrack_tcp_loose = 0 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_timestamps = 1 

    /etc/nftables.conf 中设置 synproxy 相关规则

    table inet filter { chain prerouting { type filter hook prerouting priority raw; policy accept; tcp dport { 80, 443 } tcp flags syn notrack } chain input { type filter hook input priority filter; policy accept; tcp dport { 80, 443 } ct state { invalid, untracked } synproxy mss 1460 wscale 7 timestamp sack-perm ct state invalid drop } } 

    系统默认没有启用 nftables, 用 systemctl start nftables 启用即可。

    之后再观察流量,对于每个 SYN 攻击包,仅发送一次 SYN-ACK, 攻击的强度大大的减弱了。 如下图所示:

    A \ SYN \ B \ SYN-ACK \ C 

    然而,每收到一个攻击包,相应的会发出一个回复包。 作为一台肉鸡,对此不是很认可,发出的包还是太多。 能不能识别出攻击包并直接丢弃呢?

    0x3: 更换防御策略

    现在已知 SYN flood 攻击时不会建立连接, 而正常情况下可以建立连接。 针对这一点的区别,可以将策略定为: 对于连接未成功的 IP 不允许再新建连接。

    具体来将就是在一个时间段内(下述配置中为 10 分钟), 同一 IP ,仅处理第一个 SYN 包, 后续的 SYN 包则直接丢弃。

    下面利用 nftables 规则实现此策略:

    table inet filter { # 状态为连接中的 IP 集合 set syn_staging { type ipv4_addr size 65536 flags dynamic timeout 10m } chain input_http_check { # 来自原始方向的第二个包,即 ACK ,此时连接已建立,可以移除限制 ct original packets 2 ct state established delete @syn_staging { ip saddr } ct state { established, related } accept # IP 在集合中,不允许再新建连接,直接丢弃,并计数 ip saddr @syn_staging counter drop # 将新连接的 IP 添加到集合中 ct state new update @syn_staging { ip sadr counter } } chain input { type filter hook input priority filter; policy accept; ct state invalid drop # 对 HTTP 端口的数据做检查 tcp dport { 80, 443 } jump input_http_check } } 

    设置后观察一段时间, 可以通过 nft list set inet filter syn_staging 列出集合中的 IP 。 其中计数较大的就是被攻击者的 IP 。

    在被 flood 过程中, 本方案发包数量上要少于 synproxy。 但缺点也比较明显,在网络环境较差时容易造成误封。 所以在上述规则中设置超时时间较短, 仅处理 80 和 443 端口, 以减少对其他连接的影响。

    如果有误封的情况,可以用以下命令解封: nft delete element inet filter syn_staging { 1.2.3.4 }

    0x4: 后续优化

    上述规则也可以视为一种限速策略,限制单 IP 处于连接中的连接数量为 1 。 对于流量较大的服务器来说可能会无法接受。 那么能不能将限制数量从 1 改为 2 或者更大呢? 要实现这一点,需要下面两点:

    • 对集合中计数的自减操作(上述规则使用了自加操作用于计数)
    • 判断集合中的计数大小(超过限制后丢弃、等于零则删除)

    由于目前的规则已经大大缓解了 SYN flood 攻击,就没有再继续深究。

    0x5: 总结

    借此机会又回顾了一下 TCP 三次握手过程,巩固了相关知识。 同时上手体验了一下 nftables , 相对于 iptables 来讲, 有配置结构化、易于理解的优点。

    公网上的服务器还是要有一定程度的防护的, 不能太佛系,否则会被当成肉鸡。

    另外希望攻击者对于肉鸡列表做定期有效性检验, 然后把我的服务器从列表中移除。

    2 replies    2023-03-20 09:45:02 +08:00
    datocp
        1
    datocp  
       Mar 20, 2023 via Android
    曾经有人说这是程序员专属语法,学习新东西真是累,


    -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m comment --comment "!fw3" -j syn_flood
    # iptables -S syn_flood
    -N syn_flood
    -A syn_flood -m limit --limit 100/sec --limit-burst 50 -j RETURN
    -A syn_flood -j DROP
    mdzz
        2
    mdzz  
    OP
       Mar 20, 2023
    @datocp
    OpenWrt 的规则条件定的比较高,实际流量达不到这么高,也就 2~3 分钟内几百个这样的水平,但是定低了影响正常流量。所以才设计的针对性规则
    About     Help     Advertise     Blog     API     FAQ     Solana     4058 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 168ms UTC 05:28 PVG 13:28 LAX 22:28 JFK 01:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86