火眼金睛 – Linux 系统防火墙


防火墙,顾名思义,主要任务是防止外面的“火焰”烧到内部来,具体来说,就是其根据一定的规则,阻止或放行外部的访问请求,达到对从外围企图进入内部的危险进行隔离的目的。这是一个非常宏观的概念,可以应用大至一个网络,也可以聚焦到一台主机、一个应用程序。本文重点梳理单台 Linux 主机系统防火墙的原理和应用,这是理解防火墙工作的基础;理顺了单台主机防火墙的情况,很容易进行更大规模扩展。

所有的现代操作系统,都会配备防火墙 — 一种管理经过计算机网络流量的软件。通过防火墙,在可信网络和不可信网络之间构建一道屏障。Linux 操作系统当然也不例外,在内核层面就置入了防火墙的能力。

0x01 网络数据包闯关流程

研究防火墙,首要问题躲不开缕清数据如何从外围进入内部的过程,以此才能看清防火墙工作的各个卡点或层级。

一个网络封包(package)进入 Linux 主机,从进入网卡接口到被目标进程最终接收,在 Linux 系统中要经历一些列的关卡,经历重重“磨难与考验”。

linuxfirewall-1.png

具体来说,数据包首先到达物理网络接口(如 eth0)。网卡通过 DMA 将数据包复制到内核内存中的缓冲区中。然后,网卡会产生一个硬件中断(IRQ),通知 CPU 有数据到达。CPU 会根据操作系统中防火墙的流量控制(包过滤功能)的策略对数据包进行后续的处理。

0x02 Linux 的系统防火墙

网络封包进入 Linux 主机,首先要经过 Linux 系统防火墙,做第一轮的审核与筛选。防火墙要处理网络封包,其设计思路自然也贴合 TCP/IP 四层网络模型要求,对 TCP/IP 的底层和高层都可以进行约束,Linux 系统防火墙也是基于此进行设计。其主要有两类系统防火墙:Netfilter 和 TCP Wrapper。

0x21 Netfilter

Netfilter 是内核层面的网络包过滤器,它工作在网络层和传输层,在数据包到达任何应用程序之前就进行拦截和处理。

Netfilter 的主要原理是将数据封包的表头信息(header)提取出来进行分析,并通过对封包过滤规则的制定,以此作为抓手对网络封包进行放行或者抵挡。因为其工作于网络层和传输层,所以对 MAC、IP、TCP、UDP、ICMP 等类型的封包均可以进行分析。

为方便使用,尤其是过滤规则的设置,Netfilter 提供了 iptables、nftables 等用户空间工具。

Netfilter 是 Linux 核心的内建功能,因此相较其他防火墙,其效率极高。

0x22 TCP Wrapper

TCP Wrappers 是用户层面的访问控制器,它在应用层工作,在连接已经被应用程序接收但尚未完全处理之时进行拦截。

TCP Wrapper 的主要原理是在服务器的守护进程层面(daemon,如 tcpd)对数据进行放行或拦截处理。与 Netfilter 的封包过滤机制不同,TCP Wrapper 在各种服务器进程中加入“外挂(即链接 libwrap.so 库)”,数据在进入各类服务器进程核心任务前,先通过外挂对各个服务器进程的访问情况进行分析,再利用过滤规则去决定谁可以和该服务器进程能够连线、谁不能连线。

为方便实用,TCP Wrapper 使用文本文件 /etc/hosts.allow/etc/hosts.deny 对进程的访问进行控制。

TCP Wrapper 工作在用户层,相较 Netfilter 效率较低,但是针对应用层的木马和病毒的危险,Netfilter 是无法察觉的,此时 TCP Wrapper 能发挥应用层防火墙的作用。

0x23 Netfilter 与 TCP Wrapper 运作实例比较

假设有一台运行 SSH 服务(端口22)的服务器,想禁止 IP 地址 192.168.1.100 访问。

1、使用 Netfilter (iptables) 实现

sudo iptables -A INPUT -p tcp --dport 22 -s 192.168.1.100 -j DROP

过程分析:

  • 当 192.168.1.100 发来的 TCP SYN 包到达服务器的网络接口时,内核会在 Netfilter 的 INPUT 链中检查到这个规则,并立即丢弃该数据包。SSH 服务进程(sshd)永远不会知道有这个连接尝试。对客户端来说,连接会超时或被拒绝。

2、使用 TCP Wrappers 实现

编辑 /etc/hosts.deny 文件:

sshd : 192.168.1.100

过程分析:

  • 客户端 192.168.1.100 发起 TCP 连接到 SSH 端口。
  • 内核 Netfilter 规则(如果没有其他规则阻止)会允许这个包通过,并完成 TCP 三次握手。
  • 内核将新建的连接交给 sshd 进程。
  • sshd 进程(因为它编译时链接了 libwrap.so,以此实现“外挂”)会读取 /etc/hosts.allow/etc/hosts.deny 文件。
  • 它发现规则匹配,于是主动关闭这个刚刚建立的连接。
  • 对客户端来说,连接可能已经建立,但立即被服务器断开了。

0x24 发展趋势

Netfilter 是现代 Linux 防火墙的基石。它强大、高效、功能全面,应作为主网络安全防护的首选和主要手段。

TCP Wrappers 是一种遗留技术,其设计初衷是为了在当时功能有限的内核防火墙基础上提供一个简单的访问控制层。现在它有明显的缺点:

  • 不支持 IPv6(一些扩展版本支持,但非标准)。
  • 许多新的服务(如 nginx, docker 管理的服务)默认不链接 libwrap.so,使得配置无效。
  • 依赖主机名查找时可能带来安全风险和延迟。
  • 主流发行版(如 RHEL 8/9, Ubuntu 新版本)中默认不再安装,甚至明确建议不再使用。

最佳实践上,应该专注于使用 nftables(或 iptables)来管理主机防火墙。将 TCP Wrappers 视为一个历史遗留组件,在新系统中避免使用。想达到应用层面的防火墙效用,则选用其他更优的解决方案。

0x03 Netfilter 的数据包过滤框架

网络应用中的数据,被拆分成多个更小的数据封包(package),这些封包在源点发出,利用网络进行传递,最终在目的地被重新组合为拆分前的内容。网络流量就是由一个个的数据封包组成。

连入网络的 Linux 主机,对经过自己的网络流量,即每一个网络上过来的数据封包,都要让其经过 Netfilter 的检查。

Netfilter 设置了一系列的规则,数据封包一旦与对应规则匹配,则进行对应的处理动作,例如有的包留下进一步本机使用、有的包丢弃、有的包则直接转发出去、也有的需要对数据包进行修改(如对 IP 地址进行转换)后再转发出去,Netfilter 为 Linux 内核管理网络数据包的过滤修改(即防火墙和 NAT)提供了一套框架。

linuxfirewall-filter.png

0x31 表格与链的结构

Netfilter 框架由一些列承载主要功能的表格(tables)和表格中细分的链(chains)组成,

表名称 链名称 功能
filter 类似“门卫部门”,处理进入 Linux 主机的封包。最核心、使用最频繁的表。
INPUT – 类似“入口链”,处理想进入 Linux 本机的封包,即包的目的地是 Linux 本机。
OUTPUT – 类似“出口链”,处理 Linux 本机要送出的封包,即包的源头是 Linux 本机。
FORWARD – 类似“走廊链”,处理“经过”本机但“目的地不是”本机的数据包,数据封包经过本机路由要转发到其他机器上。以快递为例,这个链处理要在 Linux 本机 “中转” 的包裹,Linux 本机作为中转站,只是负责把包裹从一个网点运到另一个网点;
– 当 Linux 本机充当路由器或网关时,这个链至关重要;
– 与 nat table 相关性高,与 Linux 本机关系不大
nat 类似“换证/登记信息的变更部门”,进行网络地址的转换,将数据包源头或目的 IP 和 port 的转换。与 Linux 本机关系不大,但与数据封包离开本机后,在后续网络中的传递密切有关
PREROUTING – 进行路由判断之前,要进行的规则(DNAT/REDIRECT)
POSTROUTING – 进行路由判断之后,要进行的规则(SNAT/MASQUERADE)
OUTPUT – 与发送出去封包有关
mangle 与特殊的封包的路由旗标有关,一般很少用到

0x32 表格与链的逻辑顺序关系

Netfilter 将表格中的各个链嵌入到数据封包进入主机的生命周期过程各个阶段,例如,封包进入主机前、进入主机后等各阶段都嵌入了对应的表链,通过表链里的规则,形成了一套严密的控制框架,以此来达到对数据封包进行管控和修改的作用。

下图展示了数据封包进出主机生命周期中,各个主要链的逻辑顺序关系,

linuxfirewall-chains.png

当一个网络封包达到主机时,内核会根据这个封包的目的地 IP 地址,使用 iptables 做出不同的路由决策,

  • 路由链路 A — 封包的目的地 IP 地址是本主机
    • 如果这个封包的目的地 IP 地址是本主机,内核会将这个封包传递给 INPUT 链;如果这个封包满足 INPUT 链中设定的所有规则,这个封包就会交给监听(listening)该类封包的本地进程处理;
  • 路由链路 B — 封包的目的地 IP 地址是另外一个网络
    • 如果这个封包的目的地 IP 地址是另外一个网络,且内核开启了 IP 转发的功能,内核则会将这个封包传递给 FORWARD 链;如果这个封包满足 FORWARD 链的所有规则,则它会被送至另一个网络;
    • 如果内核没有开启 IP 转发的功能,且封包的目的地地址不是本主机,则封包被丢弃;
  • 主机出口链路 C
    • 如果本机进程完成封包处理后,想把处理后封包送出,则会将封包传递至 OUTPUT 链;如果 OUTPUT 链的规则接受封包,会将封包传递至指定的网络;

0x04 Netfilter 管控工具 — iptables

Netfilter 为 Linux 内核提供了最基础的网络数据包过滤能力,这种能力的实现,是通过对网络封包的包头信息进行的分析与处理,而不干涉网络封包的数据段的部分。因此,网络封包过滤规则的设定,也是围绕着封包的包头信息进行约束和修改。

iptables 作为 Netfilter 在用户空间的工具,实现了一套可以对包头信息进行描述的语法,通过这套语法可以编制各种包过滤的规则,iptables 的主要任务也是对防火墙的“规则数据库”进行 CRUD 管理,其基本用法也是围绕 CRUD 的几个方面设计的。

0x41 规则查看

iptables [-t tablename] [-L] [-n] [-v]
  • 基础指令
    • -t:–table。指出具体的表名称,如 filter 或 nat。如不指定该参数,默认情况下,预设为 filter 表;
    • -L:–list。列出目前 table 下所有链中的规则;
  • 显示优化选项
    • -n:–numeric。结果用数字形式输出,反之用文字(如名称)代替数字;
    • -v:–verbose。冗余显示,显示更多信息量;

linuxfirewall-iptables.png

通过 -L 选项,可以看到防火墙某个表中(如图为 filter 表)所有的链上的所有规则(定制化的和默认的)。默认规则(policy)显示在链名称的旁边,定制化规则用 5 个元素进行描述,

  • target:表明本规则的最终目标动作,例如,放行(ACCEPT)/丢弃(DROP)/拒绝(REJECT);
  • prot:表明本规则使用的协议,tcp/udp/icmp;
  • opt:额外的选项说明;
  • source:本规则针对的封包中的 source IP;
  • destination:本规则针对的封包中的 dest IP;

iptables 显示格式化较为工整,但信息不够详细,可使用 iptable-save 查看更细粒度的防火墙信息。

iptables-save [-t tablename]

0x42 规则删除

iptables [-t tablename] [-FXZ]
  • -F:–flush;清除所有规则;
  • -X:–delete-chain;删除所有 non-builtin 的、用户自定义的规则;
  • -Z:–zero;将所有/指定的链/规则中统计的封包和比特数都清零;

这三条指令不改变默认规则/策略。

0x43 规则修改

0x431 默认规则的修改

防火墙的每一条链都有一个默认的规则(策略),这个规则是包过滤防火墙中该链的最后的比对规则,即最后的动作,是底线操作,不能被删除,只能进行修改。

iptables [-t tablename] -P [INPUT / OUTPUT / FORWARD] [ACCEPT / DROP]

0x432 定制化规则的修改

定制化规则为防火墙提供了灵活、细粒度的封包处理机制。基本的指令格式如下,

iptables [-AID 链名] 
         [-io 网络接口] 
         [-p protocol] 
         [-s 来源IP/网络] [-d 目标IP/网络]
         [--sport 端口范围] [--dport 端口范围] 
         -j [ACCEPT|DROP|REJECT|LOG]

针对防火墙规则集的宏观指令,

  • -A:–append。在指定链的最后追加一条规则;
  • -I:–insert [number]。在指定链中插入一条规则;
  • -D:–delete。在指定链中删除一条规则;

任何一条规则,其最终目标都只有一个,就是将满足规则约束条件的网络封包筛选出来,并进行处理,如完成接受、拒绝等相关的动作。所以,描述最终处理动作的参数 -j 是定制化规则中最核心的参数。

  • -j:–jump target。如果匹配本规则,则 jump(跳转)指定的目标动作。iptables 有如下的几类常规的目标动作,
    • ACCEPT:接受封包,提交 iptables 的后续进程处理;
    • DROP:抛弃封包,同时保持沉默,不做其他动作;
    • REJECT:抛弃封包,同时给封包发送者发送通知;如 “Port Unreachable”;
    • LOG:记录封包的轨迹在 /var/log/message 当中;

围绕最核心的动作,iptables 中可以添加各种限制条件,构建封包的约束规则,各种的限制条件就是通过配套的参数来描述,

  • -i:–in-interface。封包进入的网络接口;
  • -o:–out-interface。封包传送出的网络接口;
  • -p:–protocol。规则适用的协议;
  • -s:–source address。来源 IP 或网络;
  • -d:–destination address。目标 IP 或网络;
  • --sport:限制来源的端口号。端口号可以连续,如 1024:65535;
  • --dport:限制目标的端口号。端口号可以连续,如 1024:65535;

除了上述列出的宏观的、基本的封包信息约束参数外,iptables 也提供了语法对封包更细粒度的信息进行约束控制,对满足规则的封包集合进行各种粒度的调整,即“封包匹配扩展模块”,

  • -m [扩展模块名称] [模块模块选项]:–match module-name module-option;
    iptables -A INPUT -m state --state INVALID -j DROP
    iptables -A INPUT -m mac  --mac-source FC:AA:14:6A:9A:A2 -j DROP
    iptables -A INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -j DROP
    

具体的扩展模块名称和与模块对应的扩展选项可以参阅 man iptables-extensions 手册。

0x05 防火墙设定原则

0x51 默认拒绝原则

如果一台 Linux 主机作为客户端使用,一般情况下,防火墙默认原则为:允许出口流量、拒绝入口流量;只允许特定的网络封包(如特定协议、特定状态)进入主机。

如果一台 Linux 主机作为网关(路由器)使用,则它允许在其不同的网络接口间转发封包,此时,主机内核要开启 IP 转发功能,同时对防火墙的 Filter 表中 FORWARD 链进行设定(Linux 为普通路由器),或对 Nat 表的 PREROUTING 链和 POSTROUTING 链进行设定(Linux 为 nat 网关)。

0x511 防火墙对连接状态的管理

一台 Linux 主机,在不对外开放服务的情况下,防火墙为了保护本机尽可能少受外部影响,要对本机的所有连接进行管理。一般情况下,只允许本机对外主动发起的连接,并允许后续响应连接的封包进入;而拒绝外部对其自身主动连接的封包进入。如此,就要分辨出哪些是“被动的”连接,哪些是“主动的”连接。这种“主动/被动”状态信息并不能直接从单个网络数据包的某个固定字段中读取的,防火墙是基于对一连串数据包的跟踪和逻辑判断得出。

在 iptable 中,将连接的状态分为 NEWESTABLISHEDRELATEDINVALID 等几类。实现上,iptables 在内存中维护了一个“连接跟踪表”,记录了所有它看到的连接的状态。当一个新包到达时,会将其与跟踪表中的条目进行匹配,并根据包的属性和 TCP/IP 协议的状态机来更新该连接的状态。举例说明,

NEW(新连接)

  • 判断逻辑:一个数据包被标记为 NEW,当且仅当它试图启动一个新的连接。
  • 技术实现:
    • 对于 TCP 连接:一个设置了 SYN 标志位,但没有设置 ACK 标志位的数据包,会被认为是新连接的开始;
    • 对于 UDP 连接:由于UDP是无状态的,系统会将从一个源 IP /源端口发往一个目标 IP /目标端口的第一个 UDP 包视为 NEW;
    • 对于 ICMP:例如,一个 echo-request(ping请求)包会被视为 NEW;
  • 说明:NEW 指的是 iptables(conntrack)视角下的新连接,而不是指 TCP 协议握手的第一步;

ESTABLISHED(已建立的连接)

  • 判断逻辑:一个连接一旦成功建立双向通信,其后续的数据包就会被标记为 ESTABLISHED。更准确地说,只要看到双向的流量,状态就会变为 ESTABLISHED。
  • 技术实现:
    • 对于 TCP 连接:在三次握手完成之后(即看到SYN,SYN-ACK,以及最终的ACK包之后),该连接的所有后续包(包括数据包、FIN包等)都是 ESTABLISHED 状态。实际上,在收到 SYN-ACK 包并回敬 ACK 包的那个方向上,连接就已经算建立了。
    • 对于 UDP 和 ICMP:只要请求方发出了一个包(NEW),并且收到了对方的回应包,那么这条连接以及后续的通信都会被认为是 ESTABLISHED。
  • 说明:ESTABLISHED 状态匹配的是已经成功进行过双向对话的连接的流量。这是设置允许“回包”规则的基石。

RELATED(相关的连接)

  • 判断逻辑:RELATED 是一种高级状态。一个连接被标记为 RELATED,表示它是由一个已有的 ESTABLISHED 连接被动派生出来的新连接。
  • 技术实现:iptables(conntrack)通过检查数据包的应用层数据或特定协议来识别。
    • 示例 1:FTP:
      • FTP协议使用两个连接:控制连接(端口21)和数据连接(端口20或随机高端口)。当客户端通过控制连接(ESTABLISHED)发送 PORT 或 PASV 命令时,命令中包含了即将建立的数据连接的端口信息。conntrack 的辅助模块(如 nf_conntrack_ftp)会“嗅探”这个命令,了解到“一会儿会有一个从客户端X到服务器Y端口Z的连接”。当这个新的数据连接试图建立时,conntrack 能识别出它属于那个已存在的 FTP 控制连接,从而将其状态标记为 RELATED。
    • 示例 2:ICMP错误消息(如 Destination Unreachable)、某些视频流协议等。
  • 说明:RELATED 允许你安全地放行那些协议本身需要动态开启额外端口的连接。

INVALID(无效的包)

  • 判断逻辑:这个状态是个“垃圾桶”,指那些无法被识别或不符合协议逻辑的包。例如数据包看起来有问题,或者不属于任何被跟踪的连接。
  • 技术实现:原因多种多样,比如:
    • TCP包 flags 组合异常(如SYN+FIN)。
    • ICMP错误消息,但找不到其指向的原始连接。
    • 校验和错误的包。
  • 说明:通常的建议是丢弃 INVALID 状态的数据包。

连接管理的常见问题

要建立一个由端点 A 到端点 B 的连接。如果 A 能够顺利传输数据到 B 端,如 A 可以 ping 通 B,但是 B 端却无法传输数据到 A 端,如 B 无法 ping 通 A,这种情况下,大概率是 A 端的防火墙对主动入口连接进行了拒绝处理,调整 A 端的防火墙设置,才能顺利建立连接。

0x52 远程不编辑原则

尽量不要通过远程登录方式使用 iptables 命令。尤其是封包拒绝规则要小心,一旦设定顺序不当,可能导致无法通过网络继续远程访问主机,无法进行后续的操作。

0x06 iptables 的生态工具

0x61 iptables 简化版 — ufw

iptables 提供较为灵活、完备的包过滤规则表述能力的同时,使用上也相对复杂,为了简化设置与使用成本,一些 Linux 的发行版上提供较为简洁的 ufw 工具。

ufw,全名 Uncomplicated Fillwall,顾名思义,ufw 是一种“不复杂”、简化版的防火墙。本质上,ufw 可以视为 iptables 的一种前端工具。

0x62 规则保存与恢复 — iptables-save

使用 iptables 命令定义的规则,被保存在主机的内存里,随着系统重启会丢失。可以 iptable-save 工具将规则存储到一个文件中,使用时再加载回来。

# 查看规则构建命令
iptables-save

# 将规则保存
iptables-save > iptables.rules

# 将规则加载
iptables-save < iptables.rules

也可以使用脚本保存和恢复防火墙的设定。

Reference

  1. 《鸟哥的私房菜》
  2. man iptables/iptables-save/iptables-extensions
  3. https://www.dummies.com/article/technology/computers/operating-systems/linux/how-to-use-netfilter-on-your-linux-system-enabling-a-packet-filtering-firewall-255867/
  4. https://phoenixnap.com/kb/iptables-linux
  5. https://phoenixnap.com/kb/iptables-port-forwarding
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇