Linux 防火墙规则优化实战:iptables/firewalld 精准放行与防扫描加固教程

很多站长部署完网站就”万事大吉”,防火墙保持默认放行策略,直到某天在日志里看到满屏的端口扫描和暴力破解记录才慌了神。事实上,Linux 服务器面临的第一波攻击往往不是高深的漏洞利用,而是端口扫描、弱口令爆破、异常流量这些”基本功”——攻击者先扫出你开放了哪些端口,再针对性地发起爆破或漏洞探测。本文从策略设计讲起,手把手带你用 firewalld 与 iptables 搭建一套”默认拒绝、按需放行”的防火墙体系,并给出可直接执行的防扫描、限速封禁命令,让你服务器的每一扇”门”都处于受控状态。

一、先想清楚:防火墙策略设计的三个原则

动手敲命令之前,先明确三条设计原则,否则规则越多越乱,最后连自己都分不清放行了什么:

  • 默认拒绝优于默认放行:默认策略(Policy)设为 DROP,只对明确需要的端口放行。被扫描器”扫不出来”,比被扫出来后靠规则拦截更省心。
  • 最小开放原则:对外只开放 Web(80/443)和管理端口(22),数据库、Redis、面板等一律只监听内网或受信 IP,不暴露公网。很多入侵事件都是因为 3306、6379 端口裸奔公网导致。
  • 分层防护:云厂商安全组/防火墙、系统防火墙(firewalld/iptables)、应用层 WAF 三者是叠加关系,系统防火墙负责”关窗关门”,WAF 负责”拦人”。规则冲突时以最严格的为准。

另外必须理解 iptables 的规则匹配顺序:规则从上到下逐条匹配,命中即停止。所以”放行”规则要写在”拒绝”规则之前,而全局限速、防扫描规则适合放在放行规则之后兜底。顺序写反是新手最常见的错误。

顺便提醒:云服务器默认安全组一般也是放行制,改系统防火墙规则前先确认安全组没有同时放行高危端口,否则规则写了等于白写。

二、firewalld 实战:站点场景下的精准放行

CentOS 7+/Rocky/AlmaLinux 默认使用 firewalld,基于 zone(区域)管理规则,配置直观、支持运行时与永久两种状态,适合绝大多数站点场景。先确认服务状态并查看当前生效区域:

systemctl start firewalld
systemctl enable firewalld
systemctl status firewalld
firewall-cmd --get-active-zones   # 查看各区域绑定的网卡
firewall-cmd --list-all           # 查看当前区域所有规则

以最常见的 Web 站点场景为例,只放行 80/443/22 三个端口,其余一律拒绝:

firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --permanent --zone=public --add-port=22/tcp
firewall-cmd --reload

如果担心 SSH 被爆破,更稳妥的做法是默认关闭 22 端口,仅放行你办公网段的固定 IP,配合上一篇文章讲过的日志分析先确认自己的出口 IP:

# 先移除默认的 ssh 服务放行
firewall-cmd --permanent --zone=public --remove-service=ssh

# 仅放行指定来源 IP 的 22 端口(把 IP 换成你自己的出口 IP)
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="120.36.x.x" port port="22" protocol="tcp" accept'

# 同理可以限定宝塔面板端口(默认 8888)只对固定 IP 开放
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="120.36.x.x" port port="8888" protocol="tcp" accept'

firewall-cmd --reload

重要警告:执行 remove-service=ssh 前,务必先确认上一条 rich-rule 添加成功,否则 reload 后你当前这条 SSH 连接会立即断开。云服务器可以通过控制台 VNC 应急登录,实体机就只能跑机房了。谨慎起见,可以先只添加 rich-rule、不删除 ssh 服务,观察一段时间再收紧。

如果需要回退或清理误加规则,用 –remove-rich-rule 同样格式移除即可;如需端口转发(例如内网机器 8080 映射到本机 80),一条命令搞定:

firewall-cmd --permanent --zone=public --add-forward-port=port=8080:proto=tcp:toport=80
firewall-cmd --reload

三、iptables 高级规则:防扫描、限速与封禁

firewalld 处理日常放行足够,但遇到需要”精准打击”的场景(封禁 IP 段、限制连接频率、防 SYN Flood),iptables 直接操作更灵活。注意两者会互相影响,生产环境建议二选一作为主防火墙,以下规则在 iptables 场景下使用。

第一步,收紧默认策略并放行必要流量:

# 修改默认策略:INPUT/FORWARD 默认丢弃
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 放行回环与已建立的连接(避免把自己和正常访问挡掉)
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 放行 80/443/22
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

第二步,封禁日志分析中发现的恶意 IP 段(参考本站《Linux 服务器日志分析实战》先揪出攻击源):

iptables -A INPUT -s 45.155.205.0/24 -j DROP
iptables -A INPUT -s 103.79.76.0/24 -j DROP
# 查看封禁结果
iptables -L INPUT -n | grep DROP

第三步,限制 SSH 新连接频率,从源头压制暴力破解:

# 每个来源 IP 每分钟最多 5 次新建 SSH 连接,超出即丢弃
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
  -m limit --limit 5/minute --limit-burst 5 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

第四步,用 hashlimit 防端口扫描和 SYN Flood:

# 同一来源 IP 每秒 SYN 包超过 10 个即丢包(防端口扫描/半连接攻击)
iptables -A INPUT -p tcp --syn \
  -m hashlimit --hashlimit-above 10/second --hashlimit-burst 20 \
  --hashlimit-mode srcip --hashlimit-name syn-flood -j DROP

# 开启内核 SYN Cookies,抗小流量 SYN Flood
sysctl -w net.ipv4.tcp_syncookies=1
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
sysctl -p

若想审计被丢弃的流量,可加一条 LOG 规则(放在 DROP 规则之前),配合日志分析持续封堵攻击源:

iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4
# 查看丢包日志(配合 grep 过滤)
journalctl -k | grep IPT-DROP

四、规则持久化与验证

iptables 规则重启即失,必须持久化保存。Debian/Ubuntu 用 iptables-persistent,CentOS 用 iptables-services:

# Debian/Ubuntu
apt install iptables-persistent -y
iptables-save > /etc/iptables/rules.v4
iptables-restore < /etc/iptables/rules.v4   # 验证恢复

# CentOS/Rocky
yum install iptables-services -y
service iptables save

firewalld 的 –permanent 参数本身已写入配置文件,reload 后永久生效,无需额外保存。宝塔面板用户在”安全”菜单也能看到系统防火墙的端口放行列表,但面板只是入口,规则本质仍由系统防火墙执行。

最后做三层验证,确认没有把自己锁在门外:

# 1. 查看规则是否按预期生效
iptables -L -n --line-numbers
firewall-cmd --list-all

# 2. 本机测试端口连通性
curl -I http://127.0.0.1
curl -I https://127.0.0.1

# 3. 另开一个终端 SSH 保持连接,再重启防火墙服务
systemctl restart firewalld   # 确认 SSH 未断,再继续后续操作

实战建议:把命令整理为初始化脚本(如 /root/fw_init.sh),新服务器上线时直接执行,既省时间又避免漏配;同时把规则变更记录到运维文档,方便后续审计回溯。

总结

防火墙优化不是”加几条规则”的孤立操作,而是”默认拒绝 + 最小开放 + 分层联动”的系统工程。本文的配置可以直接复制到你的服务器:firewalld 负责日常放行与来源限制,iptables 负责限速封禁与防扫描,配合日志分析持续封堵攻击源,就能把服务器暴露面压到最小。需要提醒的是,防火墙只能挡住”敲门”的人,真正的高强度攻击(大流量 DDoS、CC、应用层漏洞利用)还需要 WAF 和高防 CDN 配合。如果你觉得规则维护麻烦,或服务器正遭受攻击,欢迎联系速度网络,我们提供专业的服务器安全加固与高防 CDN 防护方案,帮你把每一层防线都落到实处。

给TA打赏
共{{data.count}}人
人已打赏
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧

很多站长把防火墙当成”装好了就不管”的摆设:装完系统后放行 80、443、22 三个端口,从此再也没碰过。直到某天发现 SSH 被爆破了几万次、服务器被扫出奇怪的高危端口、或者套了 CDN 的源站被找到后直接裸奔,才想起来防火墙规则从来没优化过。防火墙不是”开了就行”,规则写得好不好,直接决定服务器在网络层是”铁桶”还是”筛子”。本文不扯理论,直接基于 CentOS 7/8 与 Ubuntu 22.04 两套主流环境,把防火墙规则优化做成三步实战:端口管理、防扫描限速、CDN 回源白名单。

一、先理清底层:firewalld 与 iptables 到底什么关系

很多新手被 firewalld、iptables、nftables 三个名词绕晕。简单说:iptables 和 firewalld 都是 netfilter 的前端管理工具,真正干活的是 Linux 内核的 netfilter 框架。iptables 是经典命令行工具,直接操作规则表;firewalld 是 CentOS 7 之后默认的服务型管理工具,它把规则按 zone(区域)组织,最终仍然翻译成 iptables/nftables 规则下发到内核。

用 firewalld 管理的好处是:规则按场景分组、支持”运行时规则”与”永久规则”分离、改完不用手动重启服务。但遇到复杂场景(限速、白名单、端口转发),firewalld 的富规则(rich rule)写法繁琐,直接落到 iptables 反而更直观。所以实际生产环境里,推荐”firewalld 管端口 + iptables 管高级规则”的混用模式,下面两节分别演示。

二、实战一:端口管理与规则收敛(firewalld)

规则优化的第一步不是”加规则”,而是”减规则”。先看看当前放行了哪些服务,把用不到的统统关掉:

# 查看当前所有放行的服务与端口
firewall-cmd --list-all
firewall-cmd --list-ports --zone=public

# 移除危险端口(示例:redis 6379、mysql 3306 默认不对外)
firewall-cmd --permanent --zone=public --remove-port=6379/tcp
firewall-cmd --permanent --zone=public --remove-port=3306/tcp

# 只放行必要端口:SSH、HTTP、HTTPS
firewall-cmd --permanent --zone=public --add-port=22/tcp
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https

# 重新加载使永久规则生效
firewall-cmd --reload

要点提醒:数据库、Redis、Memcached 这类服务永远不要直接暴露公网,要么只监听 127.0.0.1,要么用防火墙把端口限定到办公网段。对于只有指定 IP 才能访问的端口(比如宝塔面板 8888、phpMyAdmin),用富规则只放行来源:

# 只允许办公网出口 IP 访问宝塔面板端口
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="1.2.3.4/32" port protocol="tcp" port="8888" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" port protocol="tcp" port="8888" reject'
firewall-cmd --reload

# 查看富规则,确认放行在前、拒绝在后
firewall-cmd --list-rich-rules

注意规则顺序:firewalld 富规则按添加顺序匹配,放行特定 IP 的规则必须写在拒绝规则之前,否则先被 reject 拦掉,白名单就失效了。

端口到底留哪些?给一张最小化参考清单:Web 站点留 80/443;SSH 留 22(建议改高位端口并限制来源 IP);数据库 3306、Redis 6379、Memcached 11211 一律只监听内网或干脆不开;FTP 21、宝塔面板 8888、phpMyAdmin 这类管理入口,要么只对办公网段开放,要么配合面板安全入口使用。判断标准只有一条:业务不需要的端口,一个都不留。建议每季度对照 ss -lnt 的实际监听列表和防火墙放行列表做一次差异比对,多出来的立即删掉,别让”曾经临时放过”的端口变成常驻风险。

三、实战二:iptables 防端口扫描与限速(网络层加固)

端口放行收紧了,接下来处理”扫描与探测”。用 iptables 的 limit 模块对入站连接限速,能显著提高端口扫描和暴力破解的成本。下面这套规则直接追加到 INPUT 链:

# 丢弃非法状态连接
iptables -A INPUT -m state --state INVALID -j DROP

# 对新建 TCP 连接限速:每秒 20 个,超出即丢
iptables -A INPUT -p tcp --syn -m limit --limit 20/s --limit-burst 40 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# 防止 ping 洪水
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 5/s -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

# 记录被丢弃的包到系统日志,用于事后分析
iptables -A INPUT -j LOG --log-prefix "FW-DROP: " --log-level 4

需要说明的是:限速规则要放在放行规则之后、默认策略之前,并且小心误伤正常业务。如果站点高峰期并发高,把 –limit 适当调大,再观察 /var/log/messages 里 FW-DROP 的日志量微调。规则写好后立即验证:

# 保存规则(CentOS 用 iptables-save,Ubuntu 用 netfilter-persistent)
iptables-save > /etc/sysconfig/iptables

# 本机验证:扫描自己确认规则生效
nmap -sS -p 1-10000 127.0.0.1 | tail -5

# 查看规则命中次数,确认在拦截
iptables -L INPUT -v -n | head -20

四、实战三:CDN/WAF 回源白名单(防绕过的关键)

很多站长给网站套了 CDN 或云 WAF,但源站防火墙仍然对全网开放 80/443——攻击者只要绕过 CDN 找到源站 IP,防护就形同虚设。正确做法是:源站只允许 CDN/WAF 节点 IP 回源,其余来源一律拒绝。以 Cloudflare 部分回源网段为例:

# 放行 CDN 回源网段(换成你实际使用的 CDN/WAF 节点网段)
for ip in 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22; do
  iptables -A INPUT -p tcp --dport 443 -s "$ip" -j ACCEPT
done
# 放行回环与已建立连接(务必先放行,否则会掐断现有连接)
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# 其余访问 443 的来源统统记录并丢弃
iptables -A INPUT -p tcp --dport 443 -j LOG --log-prefix "NO-CDN: "
iptables -A INPUT -p tcp --dport 443 -j DROP

执行白名单前确认三件事:一是ESTABLISHED 放行必须在前;二是先把自己当前出口 IP 临时加进放行列表,别把自己关在门外;三是接入云防护后,源站 80 端口同样要收口,只放行回源网段。另外建议把回源网段写进脚本统一管理,节点 IP 更新时批量替换,避免手改遗漏。

五、总结

防火墙规则优化不是一次性工作,而是持续收敛的过程:定期用 ss -lnt 检查监听端口,对照防火墙放行清单删除无用规则;系统大版本升级时重新梳理一遍,别把老配置原样搬走。对于规则多、自己维护不过来的站点,也可以把网络层防护整体交给专业团队:速度网络提供的高防 CDN 与云 WAF 服务,自带回源 IP 收口、DDoS/CC 清洗和规则库持续更新,源站只需放行其节点网段即可,把”每月必做的规则优化”变成”接入即生效”。先把本文这三步做扎实,你的服务器在网络层就已经比 90% 的站点硬了。

给TA打赏
共{{data.count}}人
人已打赏
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
在线客服
在线客服
热线电话
QQ客服
电子邮箱
suduwangluo