[TOC]
安全是最好分层完成的事情之一。我们称之为深度安全。因此,在任何给定的公司网络上,你都会发现一个防火墙设备,它将互联网与存放面向互联网服务器的非军事区( **demilitarized zone, DMZ**)分隔开来。您还可以在DMZ 和内部 LAN 之间找到一个防火墙设备,并在每个服务器和客户机上安装防火墙软件。我们希望让入侵者尽可能难以抵达我们网络内的最终目的地。
有趣的是,在所有主流的 Linux 发行版中,只有 SUSE 发行版和 Red Hat 类型的发行版已经设置和启用了 firewalld。当你查看你的 Ubuntu 虚拟机的时候,你会发现它是完全开放的,就好像它对任何想成为入侵者的人表示衷心的欢迎一样。
# 1. 防火墙概述
在一个典型的业务环境中,特别是在大型企业中,您可能会在不同的地方遇到各种类型的 firewalld,这些 firewalld 可以提供各种类型的功能。一些例子如下:
- 将 internet 与内部网络分离的边缘设备将可路由的公共 IP 地址转换为不可路由的私有 IP 地址。他们还可以提供各种类型的访问控制来阻止未经授权的人。通过提供各种类型的数据包检查服务,它们可以帮助防止对内部网络的攻击,防止恶意软件,并防止敏感信息从内部网络泄漏到互联网。
- 大型企业网络通常被划分为子网络或子网络,每个公司部门都有一个子网来称为自己的子网络。最佳实践规定使用 firewalld 分隔子网。这有助于确保只有经过授权的人员才能访问任何给定的子网。
- 当然,您还可以在单个服务器和工作站上运行 firewalld。通过提供某种形式的访问控制,它们可以帮助防止入侵者在网络上对一台机器进行横向移动。它们还可以配置为防止某些类型的端口扫描和拒绝服务(DoS)攻击。
# 2. iptables 概述
一个常见的误解是 iptables 是 Linux 防火墙的名称。实际上,Linux 防火墙的名字叫 netfilter,每个 Linux 发行版都内置了它。我们所知道的是,iptables 只是我们可以用来管理 netfilter 的几个命令行实用程序之一。它最初是作为 Linux 内核版本2.6的一个特性引入的,所以它已经存在了很长时间。使用 iptables,你确实有一些优势:
- 它已经存在了足够长的时间,大多数 Linux 管理员已经知道如何使用它。
- 在 shell 脚本中使用 iptables 命令来创建自己的自定义防火墙配置非常容易。
- 它具有很大的灵活性,因为您可以使用它来设置一个简单的端口过滤器、路由器或虚拟专用网络。
- 它几乎在每个 Linux 发行版上都预先安装了,尽管大多数发行版都没有预先配置它。
- 它有很好的文档记录,并且在互联网上有免费的,详细的教程和书籍。
然而,正如你可能知道的,它也有一些缺点:
- Ipv4和 ipv6都需要各自特殊的 iptables 实现。因此,如果您的组织在迁移到 ipv6的过程中仍然需要运行 IPv4,那么您必须在每个服务器上配置两个 firewalld,并为每个服务器运行一个单独的守护进程(一个用于 IPv4,另一个用于 IPv6)。
- 如果您需要做 MAC 桥接,那就需要 ebtables,它是 iptables 的第三个组件,具有自己独特的语法。
- arptables,Iptables 的第四个组件,也需要它自己的守护进程和语法。
- 无论何时向正在运行的 iptables 防火墙添加规则,都必须重新加载整个 iptables 规则集,这会对性能产生巨大影响。
直到最近,只有普通的 iptables 是每个 Linux 发行版的默认防火墙管理器。它仍然出现在大多数发行版中,但是 Red Hat Enterprise Linux 7或更高版本现在使用新的 firewalld 作为一个更容易使用的前端来配置 iptables 规则。Ubuntu 提供了一个易于使用的 iptables 前端 Uncomplicated Firewall。我们将探讨的一种更新的技术是 nftables,它可以作为 Debian/Ubuntu 系统的一个选项。在 Red Hat 8/CentOS 8系统上,nftables 已经取代 iptables 作为 firewalld 的默认后端。
## 2.1 iptables 基础
Iptables 由五个规则表组成,每个规则表都有其独特的用途:
- **Filter table**(过滤表): 为了基本保护我们的服务器和客户机,这可能是我们使用的唯一表。
- **NAT table**: NAT 用于将公共因特网连接到私有网络。
- **Mangle table**: 当网络数据包通过防火墙时,用于修改它们。
- **Raw table**(原始表): 这是不需要连接跟踪的数据包。
- **Security table**(安全表): 安全表仅用于安装了 SELinux 的系统。
因为我们目前只对基本的主机保护感兴趣,所以我们暂时只看过滤器表。每个表由规则链组成,过滤器表由 `INPUT`、 `FORWARD` 和 `OUTPUT` 链组成。
> 虽然 Red Hat Enterprise Linux 7/8或更高版本确实安装了 iptables 服务,但它默认是禁用的,所以我们可以使用 firewalld。不可能同时运行 iptables 服务和 firewalld 服务,因为它们是两个完全不同的东西,完全不兼容。因此,如果您需要在 Red Hat 7/8系统上运行 iptables 服务,就必须禁用 firewalld。
但是,如果您的组织仍然使用 Red Hat 或 CentOS 的版本6运行其网络,那么您的机器仍然使用 iptables 运行,因为它们不能使用 firewalld。
首先,我们使用 `sudo iptables -l` 命令查看当前配置:
```shell
donnie@ubuntu:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
```
还记得我们说过你需要一个独立的 iptables 组件来处理 ipv6吗?这里,我们使用 `sudo ip6tables -l` 命令:
```shell
donnie@ubuntu:~$ sudo ip6tables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
```
在这两种情况下,您都可以看到没有规则,并且机器是完全开放的。不像 SUSE 和Red Hat,Ubuntu 希望你做所有建立防火墙的工作。我们将首先创建一个规则,允许我们从主机请求连接的服务器传入数据包:
```shell
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
```
命令的分解:
- `-A INPUT` :`-A` 在指定链的末尾放置一个规则,在本例中是`INPUT`链。使用`-I`可以把规则放在链条的开始。
- `-m`: 这在 iptables 模块中调用。在这种情况下,我们调用 conntrack 模块来跟踪连接状态。此模块允许 iptables 确定我们的客户机是否已经连接到另一台机器。
- `--ctstate state`: 其中 state 是用逗号分隔的要匹配的连接状态列表。\*\*ESTABLISHED\*\* 表示已经响应请求或者已经建立连接的数据包,\*\*RELATED\*\* 表示与已建立的连接有相关性的,比如FTP数据连接等。
- `-j ACCEPT`: 此规则将接受从客户机请求连接的服务器返回的数据包。
我们的新规则集是这样的:
```shell
donnie@ubuntu:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
```
接下来,我们将打开端口22,这样我们就可以通过 Secure Shell 连接:
```shell
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
```
命令的分解:
- `-p tcp`: `-p` 指示此规则影响的协议。此规则影响安全 Shell 所属的 TCP 协议。
- `--dport ssh` : `--dport` 选项指定我们希望此规则对其进行操作的目标端口。(注意,我们还可以将规则的这一部分列为 `--dport 22`,因为22是 SSH 端口。)
现在,假设我们希望这台机器是一台 DNS 服务器。为此,我们需要为 TCP 和 UDP 协议打开端口53:
```shell
sudo iptables -A INPUT -p tcp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
```
最后,我们有一个几乎完整的、可用的 INPUT 链规则集:
```shell
donnie@ubuntu:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate
RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
DROP all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
```
然而,这只是几乎完成,因为还有一件小事我们忘记了。也就是说,我们需要允许环回接口的流量。这没关系,因为它给了我们一个很好的机会,看看如果我们不想在最后插入一个规则,那么如何插入我们想要的规则。在这种情况下,我们将在 `INPUT 1`插入规则,这是 `INPUT` 链的第一个位置:
```shell
sudo iptables -I INPUT 1 -i lo -j ACCEPT
```
\>在为 `lo` 接口插入 `ACCEPT` 规则之前,您可能已经注意到 sudo 命令需要很长时间才能完成,并且您正在获取 `sudo: unable to resolve host. . .Resource temporarily unavailable`。这是因为 sudo 需要知道机器的主机名,这样它就可以知道哪些规则允许在特定的机器上运行。它使用环回接口来帮助解析主机名。如果`lo` 接口被阻塞,则 sudo 解析主机名需要更长的时间。
我们的规则集现在是这样的:
```shell
donnie@ubuntu:~$ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:domain
ACCEPT udp -- anywhere anywhere udp dpt:domain
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
```
请注意端口53默认显示domain端口名。要查看端口号而不是端口名,我们可以使用`-n`查看:
```shell
donnie@ubuntu3:~$ sudo iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:53
ACCEPT udp -- 0.0.0.0/0 0.0.0.0/0 udp dpt:53
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu3:~$
```
现在,就目前的情况来看,我们仍然允许一切通过,因为我们仍然没有创建一个规则,阻止我们没有特别允许的东西。不过,在我们这样做之前,让我们再看一些我们可能希望允许的事情。