雷灵模板

服务器被扫端口扫到烦?我用 iptables 配了一套防火墙规则,几个坑说清楚

author
·
3
0
🤖AI摘要
摘要生成中,请稍候...

起因:一台裸奔的服务器

去年双十一买了一台阿里云轻量,图便宜,装了系统就跑了个测试项目,安全组就默认开着 22、80、443。头一周没什么事,第二周开始 lastb 一看,好家伙——每天几百条 SSH 爆破记录,来自越南、俄罗斯、美国,还有一堆国内 IP。/var/log/secure 涨得飞快。

当时第一反应是改 SSH 端口,从 22 改成 22222,确实安静了两天。然后扫描器又找到了新端口。

那之后我才正经学了一下 Linux 的防火墙——iptables。网上教程很多,但写得要么太学术,要么直接甩一屏幕规则让你复制粘贴,不解释为什么。这篇文章是我边学边配的过程,重点把几个会卡住人的坑说清楚。

iptables 的基本骨架

iptables 四个表五个链,这是每个教程都会讲的。但我当时纠结了很久"四表五链"到底是什么意思,直到我在服务器上实际跑了几条规则才搞明白。

你不用一开始就记住所有表和链。记住三个就够用:

  • filter 表:控制放行还是拒绝,最常用
  • nat 表:做端口转发、内网穿透
  • mangle 表:改数据包的 TTL 之类,一般人用不到

链就是"数据包走到哪里该做什么检查"。最常用的三个链:

  • INPUT:进入本机的包(SSH、Web 请求)
  • OUTPUT:本机发出的包
  • FORWARD:经过本机转发的包(做网关/代理时用)

我配防火墙的需求很简单:只开放必要的端口,其他全拒绝,顺便防一下暴力破解和简单 DDoS。

第一个坑:规则顺序比你想象的更重要

iptables 规则是从上到下匹配,匹配到就停。我第一次配的时候写了:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP

这看起来没问题:先允许 22 端口,再拒绝全部。但后来我加了几条日志规则放在 DROP 之后,发现从来不生效——因为包已经被 DROP 拦截了,根本没走到后面。

正确的做法是用 -I 把新规则插到前面:

iptables -I INPUT 2 -p tcp --dport 3306 -j DROP

教训:-A 追加到末尾,-I 插入到指定位置。想清楚规则优先级再用。

第二个坑:规则重启就没了

iptables 规则存在内存里,rebootservice iptables restart 就没了。这是新手最容易踩的坑——配了一下午,服务器重启后发现所有规则消失,以为自己见鬼了。

保存规则有两种方式:

CentOS/RHEL 系:

service iptables save

或者手动导出:

iptables-save > /etc/sysconfig/iptables

Ubuntu/Debian 系: 默认没有 iptables 持久化工具,需要装:

apt install iptables-persistent
netfilter-persistent save

我现在养成习惯:改完规则立刻 iptables-save 确认备份,否则下次重启就得对着 history 重新敲。

第三个坑:loopback 接口别忘了放行

本地回环接口 lo(127.0.0.1)如果被防火墙拦住,一堆东西会出问题:MySQL 本地连接连不上、PHP-FPM 走 TCP 模式挂掉、Redis 连不上本地。症状非常诡异,因为 systemctl status 显示服务在跑,但就是不通。

安全做法:INPUT 链第一条就放行 lo 接口。

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

我现在的防火墙模板

配了这么多次,我现在用一套固定的模板,服务器装好就跑。关键点:先放行已建立的连接、放行 lo 接口、放行要用的端口、其余全 DROP。

# 清空所有规则(谨慎,会踢掉所有连接)
iptables -F
iptables -X

# 默认策略:INPUT 和 FORWARD DROP,OUTPUT ACCEPT
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 放行回环接口
iptables -A INPUT -i lo -j ACCEPT

# 放行已建立和相关联的连接(这个非常重要!)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 开放必要端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT   # SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT   # HTTP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT  # HTTPS

# 放行 ICMP ping(可选,调试方便)
iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

# 其余全部拒绝
iptables -A INPUT -j DROP

ESTABLISHED,RELATED 这一行最关键——没有它,你对外发出请求后,返回的数据包会被 INPUT 链挡在外面,表现出"能 ping 通但 curl 不通"的诡异现象。我在这里卡了整整一下午。

进阶:防 SSH 暴力破解

SSH 开着 22 端口始终是个隐患。除了改端口,iptables 可以用 recent 模块做速率限制:

# 60 秒内新连接超过 3 次就封 IP 300 秒
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP

这两行的逻辑是:每个新连 22 端口的 IP 都被记录到名为 SSH 的列表里,60 秒内同一个 IP 发起第 4 次连接时直接 DROP 掉,封禁持续到这个 IP 下次不再出现为止(由 --seconds 60 控制窗口)。

实际效果:lastb 的记录从每天几百条降到零星的几条,那些脚本爆破工具 60 秒内连三四次是常态,一撞墙就跑。

防止 ping 洪水

被人用 ping -f 打的时候服务器响应 ping 也很消耗资源。简单限速:

iptables -A INPUT -p icmp --icmp-type 8 -m limit --limit 1/second --limit-burst 5 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type 8 -j DROP

--limit 1/second 限制每秒最多响应一个 ping,--limit-burst 5 允许初始突发 5 个。超过就 DROP。

踩坑小结

iptables 不是什么高深东西,但第一次配的时候几个点特别容易翻车:

  1. 规则顺序——DROP 放最后,但你要确保 ACCEPT 规则写在它前面
  2. 重启丢失——配完一定要 iptables-save 并持久化
  3. lo 接口——本地回环被拦的症状非常误导人
  4. ESTABLISHED,RELATED——没有这条,出站请求的回复会被挡,curl 超时让你怀疑 DNS 出了问题
  5. 远程操作时千万别把 SSH 端口干掉了——建议配之前开个终端 tmux/screen 挂着,万一断了还能连回去

如果你不想手写 iptables,ufw(Ubuntu)和 firewalld(CentOS 7+)是上层封装,本质还是翻译成 iptables 规则。但我建议你先手写一遍理解原理,出问题排查的时候你才知道数据包到底经过了什么路径。

评论 (0)