22 - 防火墙与安全
Linux 防火墙是系统安全的第一道防线。它基于内核 netfilter 框架,在数据包经过网络协议栈时进行过滤、修改和重定向。本章涵盖 Linux 防火墙的完整生态:从传统的 iptables 到现代的 nftables,从 RHEL/Fedora 的 firewalld 到 Ubuntu/Debian 的 ufw,帮助你根据发行版和场景选择最合适的方案。
22.1 理解 netfilter 框架
Linux 防火墙基于内核中的 netfilter 框架。数据包在内核网络协议栈中经过多个 钩子点(hook points),防火墙在这些钩子点注册规则进行过滤:
网络数据包流向:
┌─────────────┐
入站 ───────> │ PREROUTING │ ────> 路由决策 ────> ┌──────────┐
└─────────────┘ │ FORWARD │
│ ┌──────────┐ └──────────┘
│ │ INPUT │ │
│ └──────────┘ │
│ │ │
本地进程 路由决策 ┌──────────┐
│ │ │POSTROUTING│ ───> 出站
│ ┌──────────┐ └──────────┘
│ │ OUTPUT │ ▲
└──────┴──────────┴─────────────────┘
| 钩子点 | 说明 |
|---|---|
| PREROUTING | 数据包进入网络栈后,路由决策前 |
| INPUT | 目的地是本机的数据包 |
| FORWARD | 经过本机转发的数据包 |
| OUTPUT | 本机发出的数据包 |
| POSTROUTING | 数据包离开网络栈前 |
22.2 iptables(传统方案)
iptables 是目前使用最广泛的防火墙工具。虽然 nftables 已成为其继任者,但有大量存量系统中运行着 iptables。
安装
# Debian / Ubuntu(预装)
which iptables
# RHEL / Fedora
sudo dnf install iptables-services
# Arch
sudo pacman -S iptables-nft # 现代内核上实际调用 nftables注意:现代 Linux 发行版上的
iptables命令可能实际上是iptables-nft,它使用 nftables 内核 API 但保留 iptables 语法。
表(Table)与链(Chain)
iptables 有五个内置表:
| 表 | 用途 | 包含的链 |
|---|---|---|
filter | 包过滤(默认表) | INPUT, FORWARD, OUTPUT |
nat | 网络地址转换 | PREROUTING, INPUT, OUTPUT, POSTROUTING |
mangle | 包修改(TTL、TOS 等) | 所有五个链 |
raw | 连接跟踪例外 | PREROUTING, OUTPUT |
security | SELinux 标记 | INPUT, FORWARD, OUTPUT |
# 语法:iptables -t 表 -A 链 匹配条件 -j 动作
# === 查看规则 ===
sudo iptables -L -v -n # 列出 filter 表所有链
sudo iptables -L -v -n --line-numbers # 带行号
sudo iptables -t nat -L -n # 查看 nat 表
sudo iptables -t mangle -L -n # 查看 mangle 表
# === 链基本操作 ===
sudo iptables -A INPUT -j DROP # 追加到 INPUT 链末尾
sudo iptables -I INPUT 1 -j ACCEPT # 插入到 INPUT 链第 1 位
sudo iptables -D INPUT 3 # 删除 INPUT 链第 3 条
sudo iptables -F INPUT # 清空 INPUT 链
sudo iptables -F # 清空所有链(小心!)
sudo iptables -Z # 计数器归零
# === 默认策略(Policy)===
sudo iptables -P INPUT DROP # 默认拒绝入站
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT基本匹配条件
# 按协议
sudo iptables -A INPUT -p tcp -j ACCEPT
sudo iptables -A INPUT -p udp -j ACCEPT
sudo iptables -A INPUT -p icmp -j ACCEPT
# 按端口
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT # 目标端口
sudo iptables -A INPUT -p tcp --sport 1024:65535 -j ACCEPT # 源端口范围
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT # 多端口
# 按 IP 地址
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT # 源 IP/网段
sudo iptables -A INPUT -d 10.0.0.1 -j ACCEPT # 目标 IP
sudo iptables -A INPUT -s 10.0.0.0/8 -j DROP # 拒绝整个网段
# 按接口
sudo iptables -A INPUT -i eth0 -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT # 回环接口
# 按状态
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 22 -j ACCEPT实用规则集
# 完整的基本防火墙规则
#!/bin/bash
# 设置默认策略
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
# 丢弃无效状态
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# 允许 ICMP (ping)
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# 允许 SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# 允许 HTTP/HTTPS
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
# 限制 SSH 连接速率(60 秒内最多 4 个新连接)
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 DROPNAT 与端口转发
# 源地址转换(SNAT/Masquerade)— 内部网络通过网关出站
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# 目的地址转换(DNAT)— 端口映射
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.0.0.5:8080
# 开启 IP 转发(路由功能)
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# 持久化:/etc/sysctl.conf 中设置 net.ipv4.ip_forward=1保存与恢复
# 保存当前规则
sudo iptables-save > /etc/iptables/rules.v4 # Debian/Ubuntu 习惯
sudo iptables-save > /etc/iptables/iptables.rules # RHEL/Arch 习惯
# 恢复规则
sudo iptables-restore < /etc/iptables/rules.v4
# 持久化服务
# Debian/Ubuntu: sudo apt install iptables-persistent
# RHEL/Fedora: sudo systemctl enable --now iptables
# Arch: 编写 systemd service 调用 iptables-restore记录被丢弃的包
# 记录被丢弃的新建连接
sudo iptables -A INPUT -m limit --limit 5/min -j LOG \
--log-prefix "iptables-drop: " --log-level 7
# 记录后丢弃
sudo iptables -A INPUT -j LOG --log-prefix "iptables-drop: "
sudo iptables -A INPUT -j DROP
# 查看日志
sudo journalctl -k | grep "iptables-drop"
sudo tail -f /var/log/kern.log | grep "iptables-drop"22.3 nftables(现代方案)
nftables 是 netfilter 团队开发的 iptables 继任者,从 Linux 3.13 开始进入主线内核。它统一了 iptables、ip6tables、arptables、ebtables 为一个工具。
nftables vs iptables
| 特性 | iptables | nftables |
|---|---|---|
| 代码库 | 多个独立工具 | 单一代码库 |
| 内核更新 | 每个匹配/目标需内核模块 | 用户态更新无需重编译内核 |
| 规则更新 | 整体替换 | 原子性增量更新 |
| IPv4/IPv6 | 分开管理 | 统一 inet 表族 |
| 语法 | 命令行选项 | 类脚本语言 |
| 性能 | 线性匹配 | 集合和映射加速 |
安装与基本操作
# 安装(各发行版不同)
# Debian/Ubuntu: sudo apt install nftables
# RHEL/Fedora: sudo dnf install nftables
# Arch: sudo pacman -S nftables
# 启用服务
sudo systemctl enable --now nftables
# 规则文件位置
# Debian/Ubuntu: /etc/nftables.conf
# RHEL/Fedora: /etc/nftables/ 目录
# Arch: /etc/nftables.confnftables 结构
nftables
└── table(表) ← 作用域
├── chain(链) ← 钩子点
│ ├── rule(规则) ← 匹配条件 + 动作
│ ├── rule
│ └── ...
├── set(集合) ← IP 列表等
└── map(映射) ← 键值对
# 基本语法
nft add table <family> <table_name>
nft add chain <family> <table_name> <chain_name> { type ... hook ... priority ... ; }
nft add rule <family> <table_name> <chain_name> <match> <statement>
# 查看规则
sudo nft list ruleset
sudo nft list table inet filter基本防火墙规则
# 编辑配置文件 /etc/nftables.conf#!/usr/sbin/nft -f
# 清空当前规则
flush ruleset
# 定义 IPv4/IPv6 统一表
table inet filter {
# === 入站链 ===
chain input {
type filter hook input priority 0; policy drop;
# 回环接口
iif lo accept
# 已建立和相关连接
ct state established,related accept
# 无效连接
ct state invalid drop
# ICMP(ping)
ip protocol icmp icmp type echo-request accept
ip6 nexthdr icmpv6 icmpv6 type echo-request accept
ip6 nexthdr icmpv6 icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept
# 允许 SSH
tcp dport 22 accept
# 允许 HTTP/HTTPS
tcp dport { 80, 443 } accept
# 记录丢弃的包
log prefix "nft-drop: " limit rate 5/minute
}
# === 转发链 ===
chain forward {
type filter hook forward priority 0; policy drop;
}
# === 出站链 ===
chain output {
type filter hook output priority 0; policy accept;
}
}# 加载规则
sudo nft -f /etc/nftables.conf
# 查看当前规则
sudo nft list ruleset
# 临时添加/删除规则
sudo nft add rule inet filter input tcp dport 8080 accept
sudo nft insert rule inet filter input position 3 tcp dport 3306 accept
sudo nft delete rule inet filter input handle 5
# 列出带 handle 号的规则(用于删除单条)
sudo nft -a list rulesetnftables 限速
# 方法一:limit 实现连接频率限制
tcp dport 22 ct state new limit rate 4/minute accept
tcp dport 22 ct state new drop
# 方法二:使用 dynamic set 实现 IP 限速
# 类似于 iptables 的 recent 模块# /etc/nftables.conf 中的限速示例
table inet rate_limit {
set ssh_v4 {
type ipv4_addr
size 65535
flags dynamic, timeout
timeout 1m
}
set ssh_v6 {
type ipv6_addr
size 65535
flags dynamic, timeout
timeout 1m
}
chain input {
type filter hook input priority 0; policy accept;
# 新 SSH 连接限速:每分钟每 IP 最多 4 次
ip saddr @ssh_v4 counter drop
ip saddr . tcp dport @ssh_v4
tcp dport 22 ct state new limit rate 4/minute accept
tcp dport 22 ct state new add @ssh_v4 { ip saddr } drop
}
}NAT 与端口转发(nftables)
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
# 端口转发 80 → 10.0.0.5:8080
tcp dport 80 dnat to 10.0.0.5:8080
# 端口转发 443
tcp dport 443 dnat to 10.0.0.5:8443
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# MASQUERADE(源地址伪装)
oifname "eth0" masquerade
}
}22.4 firewalld(RHEL/Fedora 生态)
firewalld 是 RHEL、Fedora、CentOS、AlmaLinux、Rocky Linux 的默认防火墙管理工具,基于 nftables(旧版基于 iptables)作为后端。
核心概念:Zone(区域)
每个网络接口可以分配到一个 zone,每个 zone 有独立的规则集:
# 查看默认 zone
sudo firewall-cmd --get-default-zone # 通常是 public
# 列出所有 zone
sudo firewall-cmd --get-zones
# 查看 zone 配置
sudo firewall-cmd --zone=public --list-all
# public (active)
# target: default
# interfaces: eth0
# services: dhcpv6-client ssh
# ports:
# ...
# 更改接口所属 zone
sudo firewall-cmd --zone=internal --change-interface=eth1 --permanent常用规则操作
# === 服务管理 ===
sudo firewall-cmd --list-services # 当前 zone 启用的服务
sudo firewall-cmd --get-services # 所有可用服务定义
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service={http,https,ssh} --permanent
sudo firewall-cmd --remove-service=ssh --permanent
# === 端口管理 ===
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --add-port={5000-5010}/tcp --permanent # 端口范围
sudo firewall-cmd --remove-port=8080/tcp --permanent
# === 富规则(Rich Rules)===
# 允许特定 IP 访问特定端口
sudo firewall-cmd --permanent --add-rich-rule='
rule family="ipv4" source address="192.168.1.100" port port="22" protocol="tcp" accept'
# 允许特定 IP 段
sudo firewall-cmd --permanent --add-rich-rule='
rule family="ipv4" source address="10.0.0.0/8" service name="ssh" accept'
# 速率限制
sudo firewall-cmd --permanent --add-rich-rule='
rule family="ipv4" service name="ssh" limit value="4/m" accept'
# === 重载(永久规则生效)===
sudo firewall-cmd --reload
# === 查看所有已生效规则 ===
sudo firewall-cmd --list-all
sudo firewall-cmd --list-all-zones自定义服务定义
# 创建自定义服务 XML 文件
sudo mkdir -p /etc/firewalld/services<!-- /etc/firewalld/services/myapp.xml -->
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>My Application</short>
<description>A custom web application</description>
<port protocol="tcp" port="8443"/>
<port protocol="tcp" port="9000"/>
</service># 重载后即可使用
sudo firewall-cmd --reload
sudo firewall-cmd --add-service=myapp --permanentfirewalld 区域配置文件
# 创建自定义 zone
sudo firewall-cmd --permanent --new-zone=dmz
sudo firewall-cmd --permanent --zone=dmz --add-interface=eth2
sudo firewall-cmd --permanent --zone=dmz --add-service=ssh
# 默认 zone 策略
sudo firewall-cmd --permanent --set-default-zone=dmz22.5 ufw(Uncomplicated Firewall — Debian/Ubuntu 生态)
ufw 是 Ubuntu 默认防火墙,为 iptables 提供简洁的命令行前端。
安装与启用
# Ubuntu/Debian 预装,其他发行版:
# sudo apt install ufw
# 启用(默认拒绝入站,允许出站)
sudo ufw enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
# 查看状态
sudo ufw status verbose
sudo ufw status numbered # 带编号的规则列表规则管理
# === 按服务名 ===
sudo ufw allow ssh # 允许 SSH (端口 22)
sudo ufw allow http # 允许 HTTP (端口 80)
sudo ufw allow https # 允许 HTTPS (端口 443)
# === 按端口 ===
sudo ufw allow 8080/tcp
sudo ufw allow 53/udp
sudo ufw allow 6000:6007/tcp # 端口范围
# === 按 IP ===
sudo ufw allow from 192.168.1.100
sudo ufw allow from 192.168.1.0/24 to any port 22
sudo ufw deny from 203.0.113.0/24
# === 限制(防暴力破解)===
sudo ufw limit ssh # 每 IP 30 秒最多 6 个 SSH 连接
# === 删除规则 ===
sudo ufw delete allow ssh
sudo ufw delete 3 # 按编号删除
# === 应用配置 ===
sudo ufw app list # 列出已安装的应用配置文件
sudo ufw allow 'Nginx Full' # 允许 Nginx HTTP+HTTPS
# === 日志 ===
sudo ufw logging on
sudo ufw logging medium # 可选: off, low, medium, high, full
sudo tail -f /var/log/ufw.logufw 应用配置文件
# ufw 应用配置位于 /etc/ufw/applications.d/
cat /etc/ufw/applications.d/nginx
# 自定义应用配置
sudo cat > /etc/ufw/applications.d/myapp << 'EOF'
[MyApp]
title=My Application
description=Custom application on port 9000
ports=9000/tcp|9001/udp
EOF
sudo ufw app update MyApp
sudo ufw allow MyApp22.6 推荐实践
按发行版分类
| 发行版 | 推荐工具 | 备注 |
|---|---|---|
| RHEL / Fedora / AlmaLinux | firewalld | 原生支持,与 Cockpit 集成 |
| Ubuntu / Debian | ufw 或 nftables | ufw 适合新手,nftables 适合高级用户 |
| openSUSE | firewalld 或 SuSEfirewall2 | firewalld 成为新默认 |
| Arch | nftables | 最小化安装,需手动配置 |
| Alpine | iptables 或 nftables | 需手动安装 |
| 通用服务器 | nftables | 统一语法,性能好 |
基本规则模板
无论使用哪个工具,防火墙规则应遵循相同原则:
- 默认拒绝入站:
policy DROP或default deny incoming - 允许回环接口:
iif lo accept - 允许已建立连接:
ct state established,related accept - 允许必要服务:SSH(22)、HTTP(80)、HTTPS(443) 等
- 限制敏感端口速率:为 SSH 等添加连接频率限制
- 记录异常流量:在 DROP 前添加 LOG 规则
验证防火墙规则
# 测试端口是否开放
nc -zv localhost 22
nc -zv localhost 80
# 从外部扫描(使用 nmap)
sudo nmap -p 22,80,443 server_ip
# 查看内核记录的丢弃包
sudo nft list ruleset | grep counter
sudo iptables -L -v -n | grep DROP
# 查看防火墙日志
sudo journalctl -u firewalld
sudo tail -f /var/log/ufw.log22.7 相关章节
- 23-SSH远程管理 — SSH 配置与端口访问控制
- 28-系统安全加固与审计 — 系统级安全加固、fail2ban、审计
- 13-网络配置基础 — 网络基础与配置工具
小结:Linux 防火墙经历了从 iptables 到 nftables 的演进。选择防火墙工具时,优先考虑发行版原生支持的方案:RHEL/Fedora 用 firewalld,Ubuntu 用 ufw,需要精细控制时使用 nftables。无论选择哪个工具,核心原则不变:最小开放端口、默认拒绝入站、记录异常流量。