处理CentOS服务器上的CC攻击,很多运维人员第一时间想到的是用Nginx或Lua脚本做限流,却忽略了系统防火墙firewalld本身就具备强大的七层防御能力。通过富规则(Rich Rules),我们可以直接在内核层面丢弃恶意流量,不消耗应用层资源。CC攻击的核心特征是在短时间内,某个或某几个IP对特定URL发起大量请求,导致服务器资源耗尽。我们要做的就是利用firewalld的“连接限制”和“字符串过滤”功能,精准识别并阻断这种模式。

在实际部署中,我们不需要复杂的第三方工具,只要firewalld版本在0.4.0以上,支持direct interface或富规则日志记录,就能构建一套轻量级的防御体系。下面我会从攻击特征分析、规则编写、动态联动到持久化配置,一步步拆解如何用firewalld富规则防御特定模式的CC攻击。

CC攻击的流量特征与防火墙切入点

CC攻击不同于洪水攻击,它的数据包完全符合TCP三次握手规范,请求也是合法的HTTP GET或POST。防御的关键在于识别“频率”和“行为模式”。比如,攻击者通常只请求一个耗资源的搜索接口或动态页面,User-Agent可能固定不变,请求间隔极短。传统的iptables limit模块只能基于IP做速率限制,但富规则可以结合日志分析,对包含特定字符串的请求进行计数和拦截。

firewalld的富规则本质是对iptables和ipset的抽象封装。我们可以通过富规则记录包含特定URI的请求日志,然后利用rsyslog或自定义脚本分析日志,动态将高频IP加入黑名单。这种“日志驱动”的防御模式,比单纯的连接数限制更精准,能有效区分正常用户和攻击流量。

基础环境确认与firewalld调优

在开始之前,必须确保firewalld的日志不会拖垮系统。默认情况下,firewalld拒绝的包会记录日志,如果攻击流量巨大,日志写入可能成为瓶颈。建议调整日志级别或使用单独的日志分区。

# 检查firewalld版本
firewall-cmd --version
# 调整防火墙日志速率限制(每秒最多10条,突发5条)
firewall-cmd --set-log-denied=all --log-denied=unicast --log-denied-rate=10/s:5

同时,确认内核参数能应对大量并发连接。调整net.core.somaxconn和net.ipv4.tcp_max_syn_backlog等参数,防止正常连接被攻击流量挤占。这些是防御的基础,否则防火墙规则还没生效,内核就已经丢包了。

核心防御:编写针对特定URL的富规则

假设攻击目标是“/api/search”这个接口,我们可以先用富规则记录所有访问该接口的请求,并标记来源IP。firewalld本身不支持直接匹配HTTP内容,但可以通过nftables或iptables的string模块来实现。在CentOS 7/8中,firewalld后端支持nftables,我们可以用direct规则调用string匹配。

# 添加一条direct规则,匹配请求中包含"GET /api/search"的包,并记录日志
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 80 -m string --string "GET /api/search" --algo bm -j LOG --log-prefix "CC-SEARCH: "
# 重载规则
firewall-cmd --reload

这条规则会把所有访问搜索接口的请求记录到内核日志中,前缀为“CC-SEARCH:”。接下来,我们需要一个守护脚本,实时解析日志,统计每个IP的请求频率。当某个IP在10秒内请求超过20次,就触发封禁。

动态封禁:日志解析与富规则联动

手动封禁跟不上攻击节奏,必须自动化。我们可以编写一个Python或Shell脚本,通过journalctl或tail -f监控日志。这里给出一个轻量级Shell脚本示例,利用journalctl和ipset实现快速封禁。

#!/bin/bash
# 创建ipset集合,用于存储攻击IP,超时时间600秒
firewall-cmd --permanent --new-ipset=cc_blacklist --type=hash:ip --option=timeout=600
firewall-cmd --reload

# 实时监控日志
journalctl -f -n 0 -k | grep "CC-SEARCH" | while read line; do
    # 提取IP地址(假设日志格式中包含SRC字段)
    ip=$(echo "$line" | grep -oP 'SRC=\K[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
    if [ -n "$ip" ]; then
        # 统计该IP最近10秒的请求次数
        count=$(journalctl -k --since "10 seconds ago" | grep "CC-SEARCH" | grep "$ip" | wc -l)
        if [ "$count" -ge 20 ]; then
            # 加入黑名单ipset
            firewall-cmd --ipset=cc_blacklist --add-entry="$ip"
            # 添加一条富规则拒绝该ipset中的所有IP
            firewall-cmd --permanent --add-rich-rule="rule source ipset=cc_blacklist drop"
            firewall-cmd --reload
            echo "[$(date)] Blocked $ip for CC attack on /api/search" >> /var/log/cc_defense.log
        fi
    fi
done

这个脚本的核心思路是:用journalctl实时读取内核日志,统计每个IP在滑动时间窗口内的请求次数,超过阈值就加入ipset黑名单。ipset的timeout功能让封禁自动过期,避免误伤动态IP的正常用户。富规则直接drop掉黑名单中的流量,不返回任何响应,节省服务器资源。

进阶策略:多层过滤与行为分析

单纯基于频率的防御可能会误伤通过代理访问的批量正常用户。我们可以增加更多维度,比如结合User-Agent和请求间隔。修改direct规则,把User-Agent也记录到日志中。

firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 80 -m string --string "GET /api/search" --algo bm -m string --string "User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1)" --algo bm -j LOG --log-prefix "CC-BOT: "

这样就能专门针对伪装成Googlebot的CC攻击。在脚本中,我们可以对包含特定User-Agent的日志设置更低的阈值,或者直接封禁。另外,对于POST请求的CC攻击,需要匹配请求体,firewalld的string模块默认只检查前几个字节,需要调整nf_conntrack参数或使用更底层的工具,但通常防御GET请求已经足够应对大多数场景。

还有一种高级用法是利用firewalld的“连接限制”富规则,直接限制每个IP到80端口的并发连接数。但这对于CC攻击来说粒度太粗,容易误伤。更精准的做法是限制每个IP到特定URI的“新建连接速率”。这需要用到nftables的meter功能,通过firewalld的direct passthrough来实现。

# 使用nftables限制每个IP每秒新建到/api/search的连接数不超过5个
firewall-cmd --permanent --direct --add-passthrough ipv4 -t filter -A INPUT -p tcp --dport 80 -m string --string "GET /api/search" --algo bm -m limit --limit 5/sec --limit-burst 10 -j ACCEPT
firewall-cmd --permanent --direct --add-passthrough ipv4 -t filter -A INPUT -p tcp --dport 80 -m string --string "GET /api/search" --algo bm -j DROP

这种方法直接在防火墙层面限制请求速率,不需要外部脚本,但灵活性稍差。如果攻击模式变化,调整起来比较麻烦。建议将两种方法结合:先用速率限制挡住突发流量,再用日志分析处理慢速CC攻击。

持久化与高可用注意事项

所有通过firewall-cmd添加的永久规则都会保存在/etc/firewalld/目录下。在服务器重启或firewalld服务重启后,规则会自动加载。但ipset集合需要确保在规则引用前创建,否则firewalld启动会失败。建议在/etc/firewalld/direct.xml中手动调整规则顺序,或者使用systemd服务在firewalld启动后执行初始化脚本。

对于集群环境,每台服务器都需要部署相同的防御策略。如果使用负载均衡,可以在负载均衡器上集中部署firewalld规则,但要注意日志量会非常大。更推荐的做法是各后端服务器独立防御,因为CC攻击往往针对特定应用逻辑,分散防御能减少单点压力。

监控和告警同样重要。当黑名单IP数量超过一定阈值时,应该通过邮件或消息推送通知运维人员,可能意味着攻击规模升级,需要上层WAF或清洗服务介入。firewalld的富规则防御适合中小规模攻击,对于数百Mbps以上的流量,还是需要专业设备。

规则优化与性能影响评估

string匹配会消耗CPU资源,尤其是在高并发场景下。建议将匹配规则放在INPUT链的最前端,一旦命中就直接处理,避免后续规则继续匹配。可以通过firewall-cmd --direct --get-all-rules查看规则顺序,确保drop规则在log规则之前。另外,定期清理ipset中的过期条目,虽然timeout会自动处理,但显式清理能减少内存占用。

# 查看当前所有direct规则
firewall-cmd --direct --get-all-rules
# 手动清理ipset(如果需要)
firewall-cmd --ipset=cc_blacklist --remove-entry="1.2.3.4"

在部署到生产环境前,务必在测试环境用ab或wrk工具模拟CC攻击,验证规则的有效性和系统负载。调整日志速率和统计窗口大小,找到最适合业务场景的参数。记住,没有一劳永逸的规则,需要根据实际攻击模式持续迭代。

通过这套方法,CentOS运维人员可以在不依赖第三方软件的情况下,快速构建基于firewalld的CC攻击防御体系。从日志记录到动态封禁,再到多层过滤,每一步都透明可控,既节省成本又提升了响应速度。