Skip to content

Latest commit

 

History

History
1968 lines (1172 loc) · 87.9 KB

File metadata and controls

1968 lines (1172 loc) · 87.9 KB

九、Linux 安全

保护 Linux 机器通常是一项平衡的工作。 最终的目的是保护数据不受不必要的访问。 虽然有许多方法可以实现这一目标,但我们应该采用能够产生最大保护的方法,以及最有效的系统管理。 测量攻击和漏洞表面(包括内部和外部)总是一个好的开始。 剩下的工作是建造栅栏和穿上盔甲——不要太高也不要太重。 外部的栅栏是网络防火墙。 在内部,在系统级别,我们构建应用安全策略。 这一章将介绍这两种方法,尽管平衡的艺术留给你了。

在本章的第一部分,我们将了解访问控制机制和相关的安全模块——SELinux 和 AppArmor。 在第二部分中,我们将探索包过滤框架和防火墙解决方案。

完成本章后,您将熟悉用于设计和管理应用安全框架和防火墙的工具——这是确保 Linux 系统安全的坚实的第一步。

以下是本章将涉及的主题的简要概述:

  • 理解 Linux 安全——概述 Linux 内核中可用的访问控制机制
  • 介绍 SELinux——深入了解用于管理访问控制策略的 Linux 内核安全框架
  • 引入 AppArmor——一个相对较新的安全模块,它基于安全配置文件控制应用功能
  • 使用防火墙-全面概述防火墙模块,包括netfilteriptablesnftablesfirewalldufw

技术要求

本章涵盖了相当多的主题,其中一些主题将通过大量的命令行操作进行介绍。 我们建议您同时使用 CentOS 和 Ubuntu 平台,并使用终端或 SSH 访问。 直接通过控制台访问系统是非常可取的,因为修改防火墙规则的方式可能具有破坏性。

了解 Linux 安全

保护计算机系统或网络安全的一个重要考虑因素是系统管理员控制用户和进程如何跨系统访问各种资源(如文件、设备和接口)的方法。 Linux 内核提供了一些这样的机制,统称为访问控制机制(ACMs)。 下面我们将简要描述它们。

自由访问控制

Discretionary Access Control(DAC)是与文件系统对象(包括文件、目录和设备)相关的典型 ACM。 在管理权限时,这种访问权由对象的所有者决定。 DAC 基于用户和组(主题)的身份控制对对象的访问。 根据主题的访问权限,它们还可以将权限传递给其他主题——例如,管理普通用户的管理员。

访问控制列表

访问控制列表(acl)提供控制哪些主体(如用户和组)可以访问特定的文件系统对象(如文件和目录)。

强制访问控制

强制访问控制(MAC)对主体所拥有的对象提供不同的访问控制级别。 与 DAC 不同,在 DAC 中,用户可以完全控制他们所拥有的文件系统对象,MAC 为所有文件系统对象添加了额外的标签或类别。 因此,受试者必须有适当的访问这些类别与被标记为这些类别的对象交互。 在 RHEL/CentOS 上的Security-Enhanced Linux(SELinux)和 Ubuntu/Debian 上的 AppArmor 强化了 MAC 的。

基于角色的访问控制

基于角色的访问控制(RBAC)是文件系统对象的基于权限的访问控制的替代方案。 系统管理员分配角色,这些角色对特定的文件系统对象具有访问权限,而不是权限。 角色可以基于某些业务或功能标准,并且可能具有对对象的不同访问级别。

DAC 或 MAC 中,主体可以严格根据所涉及的权限访问对象,与之相反,RBAC 模型代表了 MAC 或 DAC 上的逻辑抽象,因为主体在与对象交互之前必须是特定组或角色的成员。

多层次的安全

多层次安全(美国职业足球大联盟)是一个具体 MAC 方案主题的过程和【显示】对象文件、套接字和其他类似的系统资源。

**### 多媒体安全

多类别安全(MCS)是 SELinux 的改进版本,允许用户给文件贴上类别的标签。 MCS 在 SELinux中重用了许多 MLS 框架。

结束我们的简短演讲 ACMs 系统,我们应该注意我们的一些内部覆盖 DAC 和 ACL第四章,管理用户和组,在部分管理权限。 接下来,我们将把注意力转向 SELinux——用于 MAC 实现的一等公民。*

*# SELinux 简介

security - enhanced Linux(SELinux)是 Linux 内核中用于管理系统资源访问控制策略的安全框架。 它支持前一节中描述的 MAC、RBAC 和 MLS 模型的组合。 SELinux 是一组内核空间安全模块和用户空间命令行实用程序,它为系统管理员提供了一种机制来控制谁可以访问系统上的哪些。 SELinux 还被设计用于保护系统不受可能的错误配置和潜在的破坏进程的影响。

SELinux 的介绍了国家安全局(国家安全局)的Linux 安全模块**(【显示】lsm)内核更新。 SELinux 最终于 2000 年发布给开源社区,并从 2003 年的 2.6 内核系列开始进入 Linux。**

那么,SELinux 是如何工作的呢? 我们接下来再看这个。

使用 SELinux

SELinux 使用安全策略为系统上的应用、进程和文件定义各种访问控制级别。 安全策略是一组规则,描述什么可以访问,什么不能访问。

SELinux 对受试者受试者进行操作。 当特定的应用或进程(主题)请求访问一个文件(对象)时,SELinux 检查请求中涉及的所需权限,并强制执行相关的访问控制。 主题和对象的权限存储在一个名为Access Vector Cache(AVC)的查找表中。 AVC 是基于 SELinux策略数据库生成的。

典型的 SELinux 策略由以下资源(文件)组成,每个资源(文件)反映安全策略的一个特定方面:

  • 类型强制:已授予或拒绝策略的操作(例如,读取或写入文件)。
  • 接口:策略交互的应用接口(如日志记录)。
  • 文件上下文:策略关联的系统资源(如日志文件)。

这些策略文件使用 SELinux 构建工具一起编译,以生成特定的安全策略。 该策略被加载到内核中,添加到 SELinux 策略数据库中,并在不重新启动系统的情况下激活。

在创建 SELinux 策略时,我们通常首先在许可模式下测试它们,在此模式下会记录违规,但仍然允许。 当出现违规时,SELinux 工具集中的audit2allow实用程序可以来解决。 我们使用audit2allow产生的日志跟踪来创建策略所需的附加规则,以说明合法的访问权限。 SELinux 违规记录在/var/log/messages中,并以avc: denied作为前缀。

下一节将描述创建 SELinux 安全策略的必要步骤。

创建 SELinux 安全策略

让我们假设有一个名为packtd的守护进程,我们需要保护它以访问/var/log/messages。 为了便于说明,该守护进程有一个简单的实现:定期打开/var/log/messages文件进行写入。 使用您喜欢的文本编辑器(例如nano)将以下内容(C 代码)添加到文件中。 让我们将该文件命名为packtd.c:

Figure 9.1 – A simple daemon periodically checking logs

图 9.1 -一个简单的守护进程定期检查日志

让我们编译并构建packtd.c来生成相关的二进制可执行文件(packtd):

gcc -o packtd packtd.c

RHEL/CentOS 8 默认安装gccGNU 编译器。 否则,您可以使用以下命令安装它:

sudo yum install gcc

我们已经准备好继续执行创建packtd守护进程的步骤和所需的 SELinux 安全策略:

  1. 安装守护程序。
  2. 生成策略文件。
  3. 构建安全策略。
  4. 验证和调整安全策略。

让我们从安装我们的packtd守护进程开始。

安装守护程序

首先,我们必须为packtd守护进程创建systemd单元文件。 您可以使用您喜欢的文本编辑器(如nano)来创建相关文件。 我们将此文件命名为packtd.service:

Figure 9.2 – The packtd daemon file

图 9.2 - packtd 守护文件

将我们创建的文件复制到它们各自的位置:

sudo cp packtd /usr/local/bin/
sudo cp packtd.service /usr/lib/systemd/system/

现在,我们准备启动我们的packtd守护进程:

sudo systemctl start packtd
sudo systemctl status packtd

状态显示如下:

Figure 9.3 – The status of the packtd daemon

图 9.3 - packtd 守护进程的状态

让我们确保packtd守护进程没有被 SELinux 限制:

ps -efZ | grep packtd | grep -v grep

ps-Z选项参数检索进程的 SELinux 上下文。 命令回显信息如下:

Figure 9.4 – SELinux does not restrict the packtd daemon

图 9.4 - SELinux 不限制 packtd 守护进程

安全属性unconfined_service_t表明packtd不受 SELinux 的限制。 实际上,如果我们尾加/var/log/messages,我们可以看到packtd记录的消息:

sudo tail -F /var/log/messages

下面是输出的摘录:

Figure 9.5 – The packtd daemon's logging unrestricted

图 9.5 - packtd 守护进程的日志记录不受限制

接下来,我们将为packtd守护进程生成安全策略文件。

生成策略文件

要为packtd构建安全策略,我们需要生成相关的策略文件。 用于构建安全策略的 SELinux 工具是sepolicy。 另外,打包最终的安全策略二进制文件需要使用rpm-build实用程序。 这些命令行工具可能在你的系统上默认是不可用的,所以你可能需要安装相关的包:

sudo yum install -y policycoreutils-devel rpm-build

以下命令生成packtd的策略文件(不需要超级用户权限):

sepolicy generate --init /usr/local/bin/packtd

相关输出如下:

Figure 9.6 – Generating policy files with sepolicy

图 9.6 -使用 sepolicy 生成策略文件

接下来,我们需要重新构建系统策略,以便它包含自定义的packtd策略模块。

构建安全策略

我们将使用在前面步骤中创建的packtd.sh构建脚本。 这个命令需要超级用户权限,因为它将新创建的策略安装在系统上:

sudo ./packtd.sh

这个构建需要相对较短的时间来完成,并产生以下输出(摘录):

Figure 9.7 – Building the security policy for packtd

图 9.7 -为 packtd 构建安全策略

请注意,构建脚本使用restorecon命令(在前面的输出中突出显示)为packtd恢复默认的SELinux安全上下文。 既然已经构建了安全策略,现在就可以验证相关的权限了。

验证安全策略

首先,我们需要重新启动packtd守护进程来处理策略更改:

sudo systemctl restart packtd

packtd进程现在应该反映新的 SELinux 安全上下文:

ps -efZ | grep packtd | grep -v grep

输出显示了安全上下文的新标签(packtd_t):

Figure 9.8 – The new security policy for packtd

图 9.8 - packtd 的新安全策略

由于 SELinux 现在控制我们的packtd守护进程,我们应该在/var/log/messages中看到相关的审计跟踪,SELinux 在其中记录了系统的活动。 让我们看看关于权限问题的审计日志。 下面的命令使用ausearch实用程序获取 AVC 消息类型的最新事件:

sudo ausearch -m AVC -ts recent

我们将立即注意到packtd/var/log/messages没有读写权限:

Figure 9.9 – No read/write access for packtd

图 9.9 - packtd 没有读写权限

为了进一步查询packtd所需的权限,我们将ausearch的输出输入audit2allow,这是一个生成所需安全策略存根的工具:

sudo ausearch -m AVC -ts recent | audit2allow -R

输出提供了我们正在寻找的代码宏:

Figure 9.10 – Querying the missing permissions for packtd

图 9.10 -查询 packtd 缺少的权限

audit2allow-R``(--reference)选项调用存根生成任务,这有时可能会产生不准确或不完整的结果。 在这种情况下,可能需要一些迭代来更新、重建和验证相关的安全策略。 让我们继续进行所需的更改,就像前面建议的那样。 我们将编辑前面生成的类型强制文件(packt.te),并按照audit2allow的输出准确地添加行(复制/粘贴)。 保存文件之后,我们需要重新构建安全策略,重启packtd守护进程,并验证审计日志。 我们在重申整个流程中的最后三个步骤:

sudo ./packtd.sh
sudo systemctl restart packtd
sudo ausearch -m AVC -ts recent | audit2allow -R

这一次,SELinux 审计应该是干净的:

Figure 9.11 – No more permission issues for packtd

图 9.11 - packtd 不再有权限问题

有时,ausearch可能需要一段时间来刷新其最近的缓冲区。 或者,我们可以指定一个开始分析的时间戳,比如在我们更新了安全策略之后,使用一个相对最近的时间戳:

sudo ausearch --start 12/14/2020 '22:30:00' | audit2allow -R

现在,我们对 SELinux 安全策略的内部机制有了基本的了解。 接下来,我们将转向在日常管理任务中管理和控制 SELinux 的一些更高级别的操作。

理解 SELinux 模式

SELinux 在系统中被启用禁用。 当启用时,它以以下模式之一运行:

  • Enforcing:SELinux 有效地监控安全策略。 RHEL/CentOS 操作系统默认启用该模式。
  • Permissive:主动监控安全策略,不执行访问控制。 策略违规已登录/var/log/messages

禁用 SELinux 时,既不会监视也不会强制执行安全策略。

下面的命令获取系统上 SELinux 的当前状态:

sestatus

输出如下:

Figure 9.12 – Getting the current status of SELinux

图 9.12 -获取 SELinux 当前状态

当 SELinux 启用时,下面的命令获取当前模式:

getenforce

permissive mode中,我们得到以下输出:

Figure 9.13 – Getting the current mode of SELinux

图 9.13 -获取 SELinux 当前模式

要将强制更改为permissive mode,我们可以运行以下命令:

sudo setenforce 0

在这种情况下,getenforce命令将显示Permissive。 要切换回强制模式,我们可以运行以下命令:

sudo setenforce 1

SELinux 模式也可以通过编辑/etc/selinux/config中的SELINUX值来设置。 可能的值记录在配置文件中。

重要提示

手动编辑 SELinux 配置文件需要重新引导系统才能使更改生效。

启用 SELinux 后,系统管理员可以通过修改/etc/selinux/config:targetedminimummls中的SELINUXTYPE值来选择以下 SELinux 策略级别。 相应的值记录在配置文件中。

重要提示

默认的 SELinux 策略设置是targeted,除了mls之外,一般不建议更改此设置。

有了targeted策略后,只有专门配置为使用 SELinux 安全策略的进程才在受限(或受限)域中运行。 这些进程通常包括系统守护进程(如dhcpdsshd)和知名的服务器应用(如ApachePostgreSQL)。 所有其他(非目标)进程都不受限制地运行,并且通常用unconfined_t域类型标记。

为了完全禁用 SELinux,我们可以使用自己选择的文本编辑器(比如sudo nano /etc/selinux/config)编辑/etc/selinux/config文件,并进行以下更改:

SELINUX=disabled

或者,我们可以运行以下命令将 SELinux 模式从enforcing更改为disabled:

sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

我们可以使用以下命令检索当前配置:

cat /etc/selinux/config

使用 SELinuxdisabled,我们得到以下输出:

Figure 9.14 – Disabling SELinux

图 9.14 -禁用 SELinux

我们需要重启系统以使更改生效:

sudo systemctl reboot

接下来,让我们通过引入 SELinux上下文来研究如何做出访问控制决策。

SELinux 上下文理解

启用了 SELinux,流程和文件都贴有上下文包含额外的SELinux-specific的信息,比如用户,角色、【显示】类型(可选)。 上下文数据用于 SELinux 访问控制决策。**

**SELinux 在lsps和其他命令中添加了-Z选项,从而显示文件系统对象、进程等的安全上下文。

让我们创建一个任意文件,并检查相关的 SELinux 上下文:

touch afile
ls -Z afile

输出如下:

Figure 9.15 – Displaying the SELinux context of a file

图 9.15 -显示一个文件的 SELinux 上下文

SELinux 上下文具有以下格式—由四个字段组成的序列,由冒号(:)分隔:

USER:ROLE:TYPE:LEVEL

我们将解释 SELinux 上下文字段。

SELinux user

SELinux 用户是身份已知一组特定的政策授权角色一个特定水平指定的 MLS / MCS【显示】范围(见SELinux 水平部分的更多细节)。 每个 Linux 用户帐户都使用 SELinux 策略映射到相应的 SELinux 用户身份。 这种机制允许普通 Linux 用户继承与 SELinux 用户关联的策略限制。

Linux 用户拥有的进程接收映射的 SELinux 用户的身份,以承担相应的 SELinux角色级别

下面的命令显示 Linux 帐户与其相应的 SELinux 用户身份之间的映射列表。 该命令需要超级用户权限。 此外,semanage实用程序可与policycoreutils包一起使用,您可能需要在系统上安装该包:

sudo semanage login -l

系统与系统之间的输出可能略有不同:

Figure 9.16 – Displaying the SELinux user mappings

图 9.16 -显示 SELinux 用户映射

有关semanage命令行实用程序的更多信息,您可以参考相关的系统参考(man semanageman semanage-login)。

SELinux roles

SELinux角色是 RBAC 安全模型的一部分,它们本质上是 RBAC 的属性。 在 SELinux 上下文层次结构中,授权用户使用角色,授权角色使用类型。 在 SELinux 上下文术语中,类型指的是文件系统对象类型,domains指的是进程类型(详见SELinux 类型一节)。

以 Linux 进程为例。 SELinux角色作为和 SELinux用户之间的中间访问层。 一个可访问的角色决定哪些(即进程)可以通过角色访问。 最终,该机制控制进程可以访问哪些对象类型,从而最大限度地减少了特权升级攻击的可能性。

SELinux type

SELinux类型是 SELinux类型实施的属性——一个MAC安全结构。 对于 SELinux 类型,我们将称为进程类型,而类型称为文件系统对象类型。 SELinux 安全策略控制特定类型如何相互访问——通过域到类型访问或域到域交互。

SELinux level

SELinux级别MLS/MCS模式的属性,也是 SELinux 上下文中的一个可选字段。 级别通常是指主体对对象的访问控制的安全许可。 清除水平包括unclassifiedconfidentialsecrettop-secret,以范围表达。 一个MLS 范围表示一对水平,如果水平不同则定义为low-high,如果水平相同则定义为low。 例如,s0-s0水平与s0水平相同。 每个级别代表一个敏感性-类别对,类别是可选的。 当指定类别时,级别定义为sensitivity:category-set; 否则,它只定义为sensitivity

现在我们已经熟悉了 SELinux 上下文。 接下来,我们将从用户的 SELinux 上下文开始,看到它们的实际应用。

用于用户的 SELinux 上下文

下面的命令显示与当前用户关联的 SELinux 上下文:

id -Z

在我们的例子中,输出如下:

Figure 9.17 – Displaying the current user's SELinux context

图 9.17 -显示当前用户的 SELinux 上下文

RHEL/CentOS 中,Linux 用户默认为unconfined(不受限制),其上下文字段如下:

  • unconfined_u:用户身份
  • unconfined_r:角色
  • unconfined_t:域关联
  • s0-s0:MLS范围(相当于s0)
  • c0.c1023:类别集合,代表所有类别(从c0c1023)

接下来,我们将研究进程的 SELinux 上下文。

进程的 SELinux 上下文

显示当前 SSH 进程的 SELinux 上下文:

ps -eZ | grep sshd

该命令输出如下:

Figure 9.18 – Displaying the SELinux context for SSH-related processes

图 9.18 -显示 ssh 相关进程的 SELinux 上下文

从输出中,我们可以推断出上面的一行指的是sshd服务器进程,它以system_u用户身份、system_r角色和sshd_t域关联运行。 第二行是当前用户的 SSH 会话,即unconfined上下文。 系统守护进程通常与system_u用户和system_r角色相关联。

在结束关于 SELinux 上下文的这一节之前,我们将研究 SELinux 域转换的一个相对常见的场景,即一个域中的进程访问另一个域中的对象(或进程)。

SELinux 域转换

假设一个域中的 SELinux 安全进程请求访问另一个域中的对象(或另一个进程),那么 SELinux 域转换就发挥作用了。 除非有特定的安全策略允许相关的域转换,否则 SELinux 将拒绝访问。

由 selinux 保护的进程从一个域转换到另一个域时会调用新域的entrypoint类型。 SELinux 评估相关的入口点权限,并决定请求流程是否可以进入新域。

为了演示一个域转换场景,我们将举一个简单的例子,当用户更改其密码时使用passwd实用程序。 相关操作涉及到passwd进程与/etc/shadow(可能还有/etc/gshadow)文件之间的交互。 当用户输入(并再次输入)密码时,passwd将散列并将用户的密码存储在/etc/shadow中。

让我们来看看 SELinux 域的亲缘关系:

ls -Z /usr/bin/passwd
ls -Z /etc/shadow

对应的输出如下:

Figure 9.19 – Comparing the domain affinity context

图 9.19 -比较域关联上下文

passwd实用程序标记为passwd_exec_t类型,而/etc/shadow标记为shadow_t。 必须有一个特定的安全策略链,允许相关域从passwd_exec_t过渡到shadow_t; 否则,passwd将无法正常工作。

让我们验证一下我们的假设。 我们将使用sesearch工具来查询我们假定的安全策略:

sudo sesearch -s passwd_t -t shadow_t -p write --allow

下面是对前面命令的简要解释:

  • sesearch:搜索 SELinux 策略数据库
  • -s passwd_t:查找以passwd_t作为源的策略规则类型角色
  • -t shadow_t:查找以shadow_t为目标的策略规则类型角色
  • -p write:查找权限为write的策略规则
  • --allow:查找策略规则允许查询的权限(用-p指定)

命令回显信息如下:

Figure 9.20 – Querying SELinux policies

图 9.20 -查询 SELinux 策略

在这里,我们可以看到append create权限,正如我们正确假设的那样。

我们如何选择passwd_t源类型而不是passwd_exec_t? 根据定义,与可执行文件类型passwd_exec_t对应的类型为passwd_t。 如果我们不确定关于【病人】shadow_t文件权限类型,我们可以简单地排除源类型(-s passwd_t)sesearch解析查询和输出(例如,使用grep passwd)。

在查询安全策略时,使用sesearch工具非常方便。 有一些类似的工具用于故障诊断或管理 SELinux 配置和策略。 最著名的 SELinux 命令行实用程序之一是用于管理 SELinux 策略的semanage。 我们接下来将研究它。

管理 SELinux 策略

SELinux 提供了几个用于管理安全策略和模块的实用程序,下面的SELinux 问题故障排除一节将简要描述其中一些实用程序。 对这些工具的研究超出了本章的范围,但是我们将以semanage为例,快速回顾一些涉及安全策略管理的用例。

semanage命令的一般语法如下:

semanage TARGET [OPTIONS]

TARGET通常表示策略定义的特定名称空间(例如,loginuserportfcontextbooleanpermissive等等)。 让我们看几个例子来了解semanage是如何工作的。

启用自定义端口的安全绑定

让我们假设我们想要为自定义 SSH 端口启用 SELinux,而不是默认的22。 我们可以使用以下命令检索 SSH 端口上的当前安全记录(标签):

sudo semanage port -l | grep ssh

对于默认配置,我们将得到以下输出:

Figure 9.21 – Querying the SELinux security label for the SSH port

图 9.21 -查询 SSH 端口的 SELinux 安全标签

如果我们想在不同的端口(如2222)上启用 SSH,首先,我们需要配置相关的服务(sshd)来监听不同的端口。 我们不会在这里讨论这些细节。 这里,我们需要使用以下命令在新端口上启用安全绑定:

sudo semanage port -a -t ssh_port_t -p tcp 2222

下面是对前面命令的简要解释:

  • -a(--add):为给定类型添加一个新记录(标签)
  • -t ssh_port_t:对象的 SELinux 类型
  • -p tcp:与端口相关联的网络协议

作为前面命令的结果,针对ssh_port_t类型的新安全策略如下所示:

Figure 9.22 – Changing the SELinux security label for the SSH port

图 9.22 -更改 SSH 端口的 SELinux 安全标签

我们可以删除旧的安全标签(针对端口22),但如果禁用端口22,这就无关紧要了。 如果我们想要删除一个端口安全记录,我们可以使用以下命令:

sudo semanage port -d -p tcp 22

我们使用-d(--delete)选项来删除相关的安全标签。 要查看semanage port策略的本地定制,可以调用-C(--locallist)选项:

sudo semanage port -l -C

有关semanage port的更多信息,请参考相关系统参考(man semanage port)。 接下来,我们将研究如何修改特定服务器应用的安全权限。

修改目标服务的安全权限

semanage使用boolean命名空间来切换目标服务的特定特性。 目标服务是具有内置 SELinux 保护的守护进程。 在下面的示例中,我们希望启用 FTP over HTTP 连接。 默认情况下,Apache 的这个安全特性(httpd)是关闭的。 下面查询相关的httpd安全策略:

sudo semanage boolean -l | grep httpd | grep ftp

我们得到以下输出:

Figure 9.23 – Querying httpd policies related to FTP

图 9.23 -查询与 FTP 相关的 httpd 策略

正如我们所看到的,相关的特性——httpd_enable_ftp_server——默认为offcurrentpersisted状态目前为off: (off, off)。 我们可以使用以下命令启用它:

sudo semanage boolean -m --on httpd_enable_ftp_server

要查看semanage boolean策略的本地定制,可以调用-C(--locallist)选项:

sudo semanage boolean -l -C

新的配置现在看起来像这样:

Figure 9.24 – Enabling the security policy for FTP over HTTP

图 9.24 -启用 FTP over HTTP 的安全策略

在前面的示例中,我们使用-m(--modify)选项和semanage boolean命令来切换httpd_enable_ftp_server特性。

有关semanage boolean的更多信息,请参考相关系统参考(man semanage boolean)。 现在,让我们学习如何修改特定服务器应用的安全上下文。

修改目标服务的安全上下文

在本例中,我们希望安全 SSH 密钥存储在本地系统上的自定义位置。 因为我们的目标是一个与文件系统相关的安全策略,所以我们将在semanage中使用fcontext(文件上下文)命名空间。

查询sshd的文件上下文安全设置。

sudo semanage fcontext -l | grep sshd

以下是输出的相关摘录:

Figure 9.25 – The security context of SSH keys

图 9.25 - SSH 密钥的安全上下文

下面的命令还将/etc/ssh/keys/路径添加到与sshd_key_t上下文类型相关联的安全位置:

sudo semanage fcontext -a -t sshd_key_t '/etc/ssh/keys(/.*)?'

'/etc/ssh/keys(/.*)?'正则表达式匹配/etc/ssh/keys/目录中的任何文件,包括任何嵌套级别的子目录。 要查看semanage fcontext策略的本地自定义,我们可以调用-C(--locallist)选项:

sudo semanage fcontext -l -C

我们应该看到新的安全背景:

Figure 9.26 – The modified security context of our SSH keys

图 9.26 -修改后的 SSH 密钥的安全上下文

我们还应该初始化/etc/ssh/keys目录的文件系统安全上下文(如果我们已经创建了它):

sudo restorecon -r /etc/ssh/keys

restorecon是一个 SELinux 实用程序,用于将默认的安全上下文恢复到文件系统对象。 选项-r(或-R)指定相关路径上的递归操作。

有关semanage fcontext的更多信息,请参考相关系统参考(man semanage fcontext)。 接下来,我们将研究为特定服务器应用启用permissive mode

为目标服务启用允许模式

在本章前面的中,我们创建了一个带有安全策略的自定义守护进程(packtd)。 请参阅创建 SELinux 安全策略一节中的相关主题。 当我们处理packtd守护进程并测试其功能时,最初我们必须处理它的 SELinux 策略违规。 最终,我们修复了所需的安全策略上下文,一切正常。 在整个过程中,我们能够使用packtd运行和测试,而不需要 SELinux 因为不遵从而关闭守护进程。 然而,我们的 Linux 系统以enforcing模式运行 SELinux(默认情况下),结果是not permissive模式。 有关enforcingpermissive modes的更多信息,请参见理解 SELinux 模式部分。

那么,packtd如何可能不受限制地运行,同时又违反安全策略?

默认情况下,SELinux 是permissive到系统中任何非目标类型。 我们所说的非目标是指还没有被强制进入限制性(或受限)模式的域(类型)。

当我们为packtd守护进程构建安全策略时,我们让相关的 SELinux 构建工具为我们的域生成默认的类型强制文件(packt.te)和其他资源。 快速浏览一下packt.te文件,我们的packtd_t类型是permissive:

cat packt.te

以下是该文件的相关摘录:

Figure 9.27 – The packtd_t domain is permissive

图 9.27 - packtd_t 域是允许的

因此,packtd_t域本质上就是permissive。 限制packtd的惟一方法是从packtd.te文件中删除permissive行并重新构建相关的安全策略。 我们把这个留给你们做练习。 在这里,我们希望提出一个可能行为不端的域(在本例中是permissive),我们可以通过semanage permissive命令管理permissive类型捕获

要为单个目标管理permissive mode,可以将命令与permissive namespace一起使用semanage命令。 下面的命令列出了当前permissive mode中的所有域(类型):

sudo semanage permissive -l

在我们的例子中,我们有内置的*packtd_t域,即permissive:*

*Figure 9.28 – Displaying permissive types

图 9.28 -显示允许类型

一般来说,默认 SELinux 配置不太可能有任何permissive types

在测试或故障排除特定功能时,可以使用semanage permissive命令将一个受限制的域临时放置到permissive mode中。 例如,下面的命令在permissive mode中设置 Apache(httpd)守护进程:

sudo semanage permissive -a httpd_t

当我们查询permissive类型时,我们得到以下结果:

Figure 9.29 – Customized permissive types

图 9.29 -自定义许可类型

使用semanage permissive命令生成permissive的域或类型将显示为Customized Permissive Types

要将httpd_t域恢复为受限(受限)状态,可以使用-d(--delete)选项调用semanage permissive命令:

sudo semanage permissive -d httpd_t

注意,我们不能用semanage命令限制内置的permissive types。 如前所述,packtd_t域本质上是permissive,不能加以限制。

故障排除 SELinux 问题

即使在我们对 SELinux 相对短暂的探索过程中,我们也使用了一些工具和方法来检查安全策略的一些内部工作,以及主体(用户和进程)和对象(文件)之间的访问控制。 SELinux 的问题通常归结为行为被拒绝,或者是在特定的主体之间,或者是在一个主体和一些客体之间。 与 selinux 相关的问题并不总是很明显,也不容易进行故障排除,但是了解能够提供帮助的工具已经是解决这些问题的良好开端。

以下是其中一些工具,简要说明:

  • /var/log/messages:包含 SELinux 访问控制跟踪和策略违规的日志文件
  • audit2allow:根据被拒绝操作对应的日志轨迹生成 SELinux 策略规则
  • audit2why:提供对 SELinux 策略违规审计消息的友好翻译
  • ausearch:查询/var/log/messages策略违规
  • 列出文件系统对象及其相应的 SELinux 上下文
  • 列出进程及其相应的 SELinux 上下文
  • restorecon:恢复文件系统对象的默认 SELinux 上下文
  • seinfo:提供 SELinux 安全策略的一般信息
  • semanage:管理并提供 SELinux 策略的洞察力
  • semodule:管理 SELinux 策略模块
  • sepolicy:检查 SELinux 策略
  • sesearch:查询 SELinux 策略数据库

对于这些工具中的大多数,都有相应的系统参考(如man sesearch),它提供了关于使用该工具的详细信息。 除了这些工具,您还可以探索 SELinux 提供的大量文档。 这是如何。

访问 SELinux 文档

SELinux 有大量的文档,可以作为 RHEL/CentOS 可安装包获得,也可以通过https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/using_selinux/index在线获取(适用于 RHEL/CentOS 8)。

在 RHEL/CentOS 8 系统上安装 SELinux 文档:

sudo yum install -y selinux-policy-doc.noarch

可以使用(例如)以下命令浏览特定的 SELinux 主题:

man -k selinux | grep httpd

SELinux 是 Linux 内核中最成熟、可高度定制的安全框架之一。 然而,它相对广阔的领域和固有的复杂性可能会让许多人感到不知所措。 有时,即使是经验丰富的系统管理员,Linux 发行版的选择也可能取决于底层的安全模块。 SELinux 主要在 RHEL/CentOS 平台上可用。 Linux 内核的最新版本现在正在远离 SELinux,转而采用一种相对更轻、更有效的安全框架。 地平线上冉冉升起的新星是幻影显形。

介绍 AppArmor

AppArmor 是一个基于 MAC 模型的 LSM,它将应用限制在有限的一组资源中。 AppArmor 使用基于已加载到内核中的安全配置文件的 ACM。 每个概要文件包含一组用于访问各种系统资源的规则。 AppArmor 可以配置为enforce访问控制,也可以配置为complain访问控制违规。

通过防止已知和未知的漏洞被利用,AppArmor 主动保护应用和操作系统资源免受内部和外部威胁,包括零日攻击。

AppArmor 从 2.6.36 版本开始就内置在主流 Linux 内核中,目前随UbuntuDebianOpenSUSE以及类似的发行版一起发布。

在下面几节中。 我们将使用 Ubuntu 20.04 环境来展示一些使用 AppArmor 的实际示例。 大多数相关的命令行实用程序在安装了 AppArmor 的任何平台上都可以相同地工作。

使用 AppArmor

AppArmor 命令行实用程序通常需要超级用户特权。

使用如下命令检查 apapparmor 的当前状态:

sudo aa-status

下面是命令输出的摘录:

Figure 9.30 – Getting the status of AppArmor

图 9.30 -获取 AppArmor 的状态

aa-status(或apparmor_status)命令提供当前加载的 AppArmor 配置文件的完整列表(没有在前面的摘录中显示)。 接下来我们来看看幻影显形。

AppArmor 对概要介绍

使用 AppArmor 时,过程被剖面限制(或限制)。 在系统启动时加载 AppArmor 配置文件,并在enforce modecomplain mode中运行。 下面我们将解释这些模式。

执行模式

AppArmor 阻止在enforce mode中运行的应用执行受限制的操作。 在syslog的日志条目中通知访问违规。 Ubuntu 默认在enforce mode中加载应用概要文件。

抱怨模式

complain mode中运行的应用可以采取受限制的操作,而 AppArmor 为相关违规创建一个日志条目。 complain mode是测试 AppArmor 配置文件的理想选择。 在将配置文件切换到enforce mode之前,潜在的错误或访问违规可以被捕获并修复。

记住这些介绍性说明后,让我们创建一个带有 AppArmor 配置文件的简单应用。

创建一个配置文件

在本节中,我们将创建一个由 AppArmor 保护的简单应用。 我们希望这个练习能帮助你对幻影显形的内部工作方式有一个合理的了解。 让我们将此应用命名为appackt。 我们将使它成为一个简单的脚本,创建一个文件,写入文件,然后删除文件。 我们的目标是让 AppArmor 阻止我们的应用访问本地系统中的任何其他路径。 为了理解这一点,可以把它想象成琐碎的日志回收。

下面是appackt脚本,请原谅这个节俭的实现:

Figure 9.31 – The appackt script

图 9.31 - appackt 脚本

我们假设log目录已经存在于与脚本相同的位置:

mkdir ./log

让我们使脚本可执行并运行它:

chmod a+x appackt
./appackt

输出如下:

Figure 9.32 – The output of the appackt script

图 9.32 - appackt 脚本的输出

现在,让我们用 AppArmor 来保护和执行我们的脚本。 在我们开始之前,我们需要安装apparmor-utils包——AppArmor 工具集:

sudo apt-get install -y apparmor-utils

我们将使用一些工具来帮助创建配置文件:

  • aa-genprof:生成一个 AppArmor 安全配置文件
  • aa-logprof:更新一个 AppArmor 安全配置文件

我们使用aa-genprof在运行时监视应用,并让 AppArmor了解。 在这个过程中,我们会被提示承认并选择在特定情况下需要的行为。

一旦创建了概要文件,我们将使用aa-logprof实用程序在complain mode中进行测试时进行进一步的调整,以防出现任何违反。

让我们从aa-genprof开始。 我们需要两个终端:一个用于aa-genprof监控会话(在终端 1中),另一个用于运行脚本(在终端 2中)。

我们将从终端 1开始,并运行以下命令:

sudo aa-genprof ./appackt

第一个提示符在等着我们。 接下来,当终端 1提示符等待时,我们将切换到终端 2并运行以下命令:

./appackt

现在我们必须回到终端 1,回答aa-genprof发送的提示,如下:

提示 1 -等待扫描

此提示要求扫描系统日志以发现 AppArmor 事件,以便检测可能的投诉(违规)。

:S(T1):

Figure 9.33 – Prompt 1 – Waiting to scan with aa-genprof

图 9.33 -提示 1 -等待用 aa-genprof 进行扫描

让我们看看下一个提示符。

提示 2 -执行/usr/bin/bash 的权限

这个提示请求运行应用的进程(/usr/bin/bash)的执行权限。

:I(T1):

Figure 9.34 – Prompt 2 – Execute permissions for /usr/bin/bash

图 9.34 - Prompt 2 -执行/usr/bin/bash 的权限

让我们看看下一个提示符。

Prompt 3 – Read/write permissions to /dev/tty

提示请求应用控制终端的读写权限(/dev/tty)。

:A(T1):

Figure 9.35 – Prompt 3 – Read/write permissions to /dev/tty

Figure 9.35 – Prompt 3 – Read/write permissions to /dev/tty

现在,让我们看看最后一个提示符。

提示 4 -保存更改

提示符要求保存或检查更改。

:S(T1):

Figure 9.36 – Prompt 4 – Save changes

图 9.36 -提示 4 -保存更改

此时,我们已经用aa-genprof完成扫描,可以用F (Finish)回答最后一个提示。 我们的应用(appackt)现在被complain mode强制执行(默认)。 如果我们尝试运行我们的脚本,我们将得到以下输出:

Figure 9.37 – The first run of appackt with AppArmor confined

图 9.37 -第一次使用禁闭的 appack

正如输出结果所表明的那样,事情还不完全正确。 这就是aa-logprof工具发挥作用的地方。 对于其余步骤,我们只需要一个终端窗口。

让我们运行aa-logprof命令来进一步优化appackt安全配置文件:

sudo aa-logprof

我们将再次得到几个提示,类似于前面的提示,要求我们的脚本需要更多的权限,即touchcatrm命令。 提示符根据需要在InheritAllow答案之间交替。 由于篇幅有限,我们在这里就不细讲了。 到目前为止,您应该对这些提示及其含义有了大致的了解。 但是,总是建议考虑所请求的权限并相应地采取行动。

我们可能需要运行aa-logprof命令几次,因为在每次迭代时,将发现并处理新的权限,这取决于脚本生成的子进程,等等。 最终,appackt脚本将成功运行。

在前面描述的迭代过程中,我们可能会在 AppArmor 数据库中得到几个未知的或孤立的条目,它们是我们之前尝试的产物,以确保应用的安全:

*Figure 9.38 – Remnants of the iterative process

图 9.38 -迭代过程的残余

它们都将根据我们的应用(/home/packt/appackt)的路径命名。 我们可以用下面的命令清理这些条目:

sudo aa-remove-unknown 

现在,我们可以验证我们的应用确实受到了 AppArmor 的保护:

sudo aa-status

输出的相关摘录如下:

Figure 9.39 – appackt in complain mode

图 9.39 - appackt 在抱怨模式

正如所料,我们的应用(/home/packt/appackt)以complain模式显示。 另外两个是系统应用相关的,与我们无关。

接下来,我们需要验证我们的应用是否符合 AppArmor 执行的安全策略。 让我们编辑appackt脚本,并将第 6 行中的LOG_FILE路径更改为以下内容:

LOG_FILE="./logs/appackt"

我们已经将输出目录从log更改为logs。 让我们创建logs目录并运行我们的应用:

mkdir logs
./appackt

前面的输出表明appackt正试图访问 AppArmor 允许的边界之外的路径,因此验证了我们的配置文件:

Figure 9.40 – appackt acting outside security boundaries

图 9.40 - appackt 在安全边界之外

让我们恢复前面的更改,让appackt脚本正常运行。 我们现在已经准备好enforce我们的应用,通过以下命令改变它的配置文件模式:

sudo aa-enforce /home/packt/appackt

输出如下:

Figure 9.41 – Changing the appackt profile to enforce mode

图 9.41 -改变 appackprofile 到强制模式

我们可以使用下面的命令来验证我们的应用确实是在enforce模式下运行:

sudo aa-status

相关输出如下:

Figure 9.42 – appackt running in enforce mode

图 9.42 - appackt 在强制模式下运行

如果我们想要对我们的应用进行进一步的调整,然后用相关的更改对它进行测试,那么我们必须将概要文件模式更改为complain,然后重申本节中前面描述的步骤。 将应用应用配置文件设置为complain mode:

sudo aa-complain /home/packt/appackt

AppArmor 配置文件是存储在/etc/apparmor.d/目录中的纯文本文件。 创建或修改 AppArmor 配置文件通常需要使用aa-genprofaa-logprof工具手动编辑本节描述的相应文件或过程。

**接下来,让我们看看如何禁用或启用 AppArmor 应用配置文件。

禁用和启用配置文件

有时,我们可能想要禁用有问题的应用概要文件,而正在开发更好的版本。 我们是这样做的。

首先,我们需要定位想要禁用的应用概要文件(例如,appackt)。 相关文件在/etc/apparmor.d/目录中,它是根据其完整路径命名的,用圆点(.)而不是斜杠(/)。 在我们的示例中,文件是/etc/apparmor.d/home.packt.appackt

要禁用配置文件,我们必须运行以下命令:

sudo ln -s /etc/apparmor.d/home.packt.appackt /etc/apparmor.d/disable/
sudo apparmor_parser -R /etc/apparmor.d/home.packt.appackt

如果我们运行aa-status命令,我们将不再看到appackt概要文件。 相关的配置文件仍然存在于文件系统中/etc/apparmor.d/disable/home.packt.appackt:

Figure 9.43 – The disabled appackt profile

图 9.43 -被禁用的 appack 配置文件

在这种情况下,appackt脚本不受任何限制强制执行。 要重新启用相关的安全配置文件,我们可以运行以下命令:

sudo rm /etc/apparmor.d/disable/home.packt.appackt
sudo apparmor_parser -r /etc/apparmor.d/home.packt.appackt

appackt配置文件现在应该显示在aa-status输出中,因为运行在complain mode中。 我们可以通过以下方式将其带入enforce mode:

sudo aa-enforce /home/packt/appackt

除了相关的文件系统操作外,我们还使用了apparmor_parser命令来禁用或启用该概要文件。 此实用程序帮助在内核中加载(-r--replace)或卸载(-R--remove)安全配置文件。

删除 AppArmor 安全配置文件在功能上等同于禁用它们。 我们也可以选择从文件系统中完全删除相关文件。 如果我们删除一个配置文件而不首先从内核中删除它(使用apparmor_parser -R),我们可以使用aa-remove-unknown命令来清除孤立的条目。

让我们用一些最后的想法来总结我们对 AppArmor 内部结构的相对简短的研究。

最后一点

与 SELinux 相比,使用 AppArmor 相对容易一些,特别是在生成安全策略或在permissive modenon-permissive mode之间来回切换时。 SELinux 只能为整个系统切换许可上下文,而 AppArmor 可以在应用级别切换。 另一方面,在这两者之间可能没有选择,因为一些主要的 Linux 发行版要么支持其中一个,要么支持另一个。 AppArmor 是 Debian、Ubuntu 和最近的 OpenSUSE 的一个奇迹,而 SELinux 运行在 RHEL/CentOS 上。 理论上,你可以尝试在不同的发行版之间移植相关的内核模块,但这并不是一个简单的任务。

作为最后的说明,我们应该重申,在 Linux 安全的大背景下,SELinux 和 AppArmor 是acm,在应用级别上对系统进行本地操作。 当涉及到保护应用和计算机系统不受外部世界影响时,防火墙就起作用了。 下面我们来看看防火墙。

使用防火墙工作

传统上,防火墙是一种位于两个网络之间的网络安全设备。 它监视网络流量并控制对这些网络的访问。 一般来说,防火墙保护本地网络不受外来入侵或攻击。 但防火墙也可以阻止针对公共互联网的不请自来的本地流量。 从技术上讲,防火墙根据特定的安全规则允许或阻止进出网络流量。

例如,除了一组选择的入站网络协议(如 SSH 和 HTTP/HTTPS)外,防火墙可以阻止所有的网络协议。 它也可能阻止所有在本地网络中除了批准的主机建立特定的出站连接,例如允许出站 SMTP 连接只起源于本地电子邮件服务器。

下图显示了一个简单的防火墙部署,调节本地网络和互联网之间的流量:

Figure 9.44 – A simple firewall diagram

图 9.44 -一个简单的防火墙图

外向的安全规则防止坏的行为者,如被入侵的电脑和不值得信任的个人,直接攻击公共互联网。 由此产生的保护有利于外部网络,但它最终对组织也是必不可少的。 阻止来自本地网络的敌对行动,可以避免它们被**互联网服务提供商****(isp)**标记为不受约束的互联网流量。

配置防火墙通常需要一个作用于全局范围的默认安全策略,然后根据端口号(协议)、IP 地址和其他标准配置该通用规则的特定例外。

在下面的部分中,我们将探索各种防火墙实现和防火墙管理器。 首先,让我们通过介绍 Linux 防火墙链来简要地了解防火墙是如何监视和控制网络流量的。

了解防火墙链

在较高的层次上,Linux 内核中的 TCP/IP 栈通常执行以下工作流:

  • 从应用(进程)接收数据,将数据序列化为网络数据包,并根据各自的 IP 地址和端口将数据包发送到网络目的地
  • 从网络接收数据,将网络数据包反序列化为应用数据,并将应用数据发送给一个进程

理想情况下,在这些工作流中,Linux 内核不应该以任何特定的方式改变网络数据,除了根据 TCP/IP 协议对其进行整形。 然而,在分布式和可能不安全的网络环境中,数据可能需要进一步检查。 内核应该提供必要的钩子来根据各种条件进一步过滤和修改数据包。 这就是防火墙和其他网络安全和入侵检测工具发挥作用的地方。 它们适应内核的 TCP/IP 包过滤接口,并对网络包执行所需的监视和控制。 Linux 内核的网络包过滤过程的蓝图也被称为防火墙防火墙链:

Figure 9.45– The Linux firewall chain

图 9.45 - Linux 防火墙链

当进入的数据进入防火墙包过滤链时,根据包的目的地做出路由决策。 基于该路由决定,包可以遵循INPUT链(对于本地主机)或FORWARD链(对于远程主机)。 这些链可以通过网络安全工具或防火墙实现的钩子以各种方式改变传入的数据。 默认情况下,内核不会改变遍历链的包。

INPUT链最终将数据包送入本地应用进程消耗数据。 这些本地应用通常是用户空间进程,例如网络客户机(例如 web 浏览器、SSH 和电子邮件客户机)或网络服务器(例如 web 和电子邮件服务器)。 它们也可能包括内核空间进程,例如内核的网络文件系统(NFS)。

FORWARD链和本地进程在将数据包放到网络上之前,都将数据包路由到OUTPUT链。

任何一条链都可以根据特定的条件过滤数据包,如下所示:

  • 源或目的 IP 地址
  • 源或目的端口
  • 数据事务中涉及的网络接口

每个链都有一组与输入数据包匹配的安全规则。 如果匹配,则内核将数据包路由到该规则指定的目标。 一些预定义的目标包括:

  • ACCEPT:接受数据包进行进一步处理
  • REJECT:拒绝数据包
  • DROP:忽略该数据包
  • QUEUE:将数据包传递给用户空间进程
  • RETURN:停止对数据包的处理,将数据返回到上一个链

要获得预定义目标的完整列表,请参考iptables-extensions系统参考(man iptables-extensions)。

在下面的部分中,我们将基于内核的网络堆栈和防火墙链探索一些最常见的网络安全框架和工具。 我们将从netfilter开始——Linux 内核的包过滤系统。 接下来,我们来看看iptables-用于配置 netfilter的传统接口。 iptables是一种高度可配置、灵活的防火墙解决方案。 然后,我们将简要介绍nftables,这是一个实现iptables大部分复杂功能的工具,它将iptables包装到一个相对易于使用的命令行界面中。 最后,我们将离开内核与包过滤框架的直接关系,看看防火墙管理器-firewalld (RHEL/CentOS)和ufw(Debian/Ubuntu)——两个用户友好的前端,用于在主要 Linux 发行版上配置 Linux 防火墙。

让我们从netfilter开始。

介绍 netfilter

netfilter是 Linux 内核中的一个包过滤框架,它提供了高度可定制的处理程序(或钩子)来控制与网络相关的操作。 这些操作包括以下内容:

  • 接受或拒绝数据包
  • 包路由和转发
  • 网络地址和端口转换(NAT/NAPT)

实现netfilter框架的应用使用一组围绕着钩子构建的回调函数,这些钩子注册在操纵网络堆栈的内核模块中。 这些回调函数进一步映射到安全规则和概要文件,这些规则和概要文件控制遍历网络链的每个包的行为。

防火墙应用是netfilter框架实现的一等公民。 因此,对netfilter钩子的良好理解将有助于 Linux 高级用户和管理员创建可靠的防火墙规则和策略。

下面我们将简要介绍这些netfilter钩子。

netfilter 钩子

当数据包穿越网络堆栈中的各种链时,netfilter会触发内核模块的事件,这些内核模块被相应的钩子注册。 这些事件导致模块或包过滤应用(例如防火墙)中实现钩子的通知。 接下来,应用根据特定的规则控制数据包。

包过滤应用有 5 个 netfilter钩子可用。 每一个都对应一个组网链,如图 9.44 所示:

  • NF_IP_PRE_ROUTING:由进入网络堆栈的流量触发,并且在路由决定将数据包发送到哪里之前触发
  • NF_IP_LOCAL_IN:当包有一个本地主机目的地时,路由一个传入包后触发
  • NF_IP_FORWARD:当报文有远端主机目的地时,路由入报文后触发
  • NF_IP_LOCAL_OUT:由本地发起的出方向流量进入网络栈触发
  • NF_IP_POST_ROUTING:由发送或转发的流量触发,该流量在路由之后,在它退出网络堆栈之前

内核模块或用netfilter钩子注册的应用必须提供一个优先级编号,以确定触发钩子时模块被调用的顺序。 这种机制允许我们确定性地对已注册到特定钩子中的多个模块(或同一模块的多个实例)排序。 当一个已注册的模块处理完一个信息包后,它会向 netfilter框架提供一个关于该如何处理信息包的决策。

netfilter框架的设计和实现是一个社区驱动的协作项目,作为自由开源软件(自由/开源软件)运动的一部分。 对于netfilter项目的一个好的起点,你可以参考到http://www.netfilter.org/

netfilter最著名的实现之一是iptables——一个广泛使用的防火墙管理工具,它与netfilter包过滤框架共享一个直接接口。 对iptables的实际检查将进一步揭示netfilter的功能方面。 接下来让我们一起探索iptables

与 iptables 一起工作

iptables是一个相对低级的 Linux 防火墙解决方案和命令行实用程序,它使用netfilter链来控制网络流量。 iptables规则结合操作。 规则定义了匹配遍历特定链的信息包的标准。 iptables使用根据标准或决策类型组织规则。 iptables定义了以下表:

  • filter:默认表,当我们决定是否允许数据包通过特定的链(INPUTFORWARD,``OUTPUT)时使用。
  • nat:用于需要源或目的地址/端口转换的报文。 该表对以下链进行操作:PREROUTINGINPUTOUTPUTPOSTROUTING
  • mangle:用于涉及 IP 报头的特殊报文改变(如MSS=最大段大小或TTL=生存时间)。 该表支持以下链:PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING
  • raw:在禁用特定数据包的连接跟踪(NOTRACK)时使用,主要用于无状态处理和性能优化目的。 该表与PREROUTINGOUTPUT链相关。
  • security:当报文受 SELinux 策略约束时,用于MAC。 该表与INPUTFORWARDOUTPUT链相互作用。

下图总结了iptables中支持的相应链表:

Figure 9.46 – Tables and chains in iptables

图 9.46 - iptables 中的表和链

数据包在内核网络栈中的链遍历顺序如下:

  • 本地主机目的地的入包:PREROUTING|INPUT
  • 远程主机目的地的入包:PREROUTING|FORWARD|POSTROUTING
  • 本地生成的报文(由应用进程):OUTPUT|POSTROUTING

既然我们已经熟悉了一些介绍性的概念,我们可以处理一些实际的例子来理解iptables是如何工作的。

下面的示例使用 RHEL/CentOS 8 系统,但是它们应该适用于所有主流 Linux 发行版。 请注意,从 RHEL/CentOS 7 开始,默认的防火墙管理应用是firewalld(在本章后面讨论)。 如果您想使用iptables,首先需要禁用firewalld:

sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl mask firewalld

接下来,安装iptables-services包(CentOS):

sudo yum install iptables-services

(在 Ubuntu 上,你必须安装iptablessudo apt-get install iptables)。

现在,我们开始配置iptables

配置 iptables

iptables命令需要超级用户权限。 首先,让我们检查当前的iptables配置。 对于一个特定的检索中的规则的一般语法如下:

sudo iptables -L [CHAIN] [-t TABLE]

-L(--list)选项列出了中的规则。 选项-t(--table)指定一个CHAINTABLE参数是可选的。 如果省略了CHAIN选项,那么所有的链及其相关规则将被考虑在一个表中。 当没有指定TABLE选项时,假设使用filter表。 因此,下面的命令列出了filter表的所有链和规则:

sudo iptables -L

在默认配置防火墙的系统中,输出如下:

Figure 9.47 – Listing the current configuration in iptables

图 9.47 -在 iptables 中列出当前配置

我们可以更具体一些,例如,通过下面的命令列出nat表的所有INPUT规则:

sudo iptables -L INPUT -t nat

-t(--table)选项参数仅在iptables操作的目标不是默认的filter表时才需要。

重要提示

除非指定了-t(--table)选项参数,否则iptables默认采用filter表。

当你从头开始设计防火墙规则时,通常建议以下步骤:

  1. 刷新当前防火墙配置中的任何残留物。
  2. 设置默认防火墙策略。
  3. 创建防火墙规则,确保将更具体(或限制性)的规则放在首位。
  4. 保存配置。

让我们通过使用filter表创建一个示例防火墙配置,来简要地了解前面的每个步骤。

步骤 1 -刷新现有配置

下面的命令将刷新filter表链(INPUTFORWARDOUTPUT中的规则:

sudo iptables -F INPUT
sudo iptables -F FORWARD
sudo iptables -F OUTPUT

除非出现错误,或者使用-v(--verbose)选项调用iptables命令,否则前面的命令不会产生输出; 例如:

sudo iptables -v -F INPUT

输出如下:

Figure 9.48 – Flushing the INPUT chain in iptables

图 9.48 -刷新 iptables 中的 INPUT 链

接下来,我们将设置防火墙的默认策略。

步骤 2 -设置默认防火墙策略

默认情况下,iptables允许所有包通过网络(防火墙)链。 安全防火墙配置应该使用DROP作为相关链的默认目标:

sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT DROP

选项参数-P(--policy)将特定链(如INPUT)的策略设置为给定目标(例如DROP)。 DROP目标使系统正常忽略所有报文。

此时,如果我们要保存防火墙配置,系统将不会接受任何传入或传出的数据包。 因此,如果我们使用 SSH 或没有直接的控制台访问,我们应该小心不要不经意地放弃对系统的访问。

接下来,我们将设置防火墙规则。

步骤 3—创建防火墙规则

让我们创建一些示例防火墙规则,例如接受 SSH、DNS 和 HTTPS 连接。

下面的命令使能从本地网络(192.168.0.0/24)访问 SSH:

sudo iptables -A INPUT -p tcp --dport 22 -m state \
 --state NEW,ESTABLISHED -s 192.168.0.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 22 -m state \
 --state ESTABLISHED -s 192.168.0.0/24 -j ACCEPT

让我们解释一下在前面的代码块中使用的参数:

  • -A INPUT:指定要将规则添加到的链(例如INPUT)
  • -p tcp:传输报文的网络协议,如tcpudp
  • --dport 22:报文的目的端口
  • --sport 22:报文的源端口
  • -m state:我们想要匹配的数据包属性(例如state)
  • --state NEW,ESTABLISHED:要匹配的报文状态
  • -s 192.168.0.0/24:报文的源 IP 地址/掩码
  • -j ACCEPT:目标或对数据包(如ACCEPTDROPREJECT等)做什么

我们使用两个命令来启用 SSH 访问。 第一个允许传入的 SSH 流量(--dport 22)用于新的和现有的连接(-m state --state NEW,ESTABLISHED)。 第二条命令为现有连接(-m state –state ESTABLISHED)开启 SSH 响应流量(--sport 22)。

同样,下面的命令可以启用 HTTPS 流量:

sudo iptables -A INPUT -p tcp --dport 443 -m state \
 --state NEW,ESTABLISHED -j ACCEPT
sudo iptables -A INPUT -p tcp --sport 443 -m state \
 --state ESTABLISHED,RELATED -j ACCEPT

为了启用 DNS 流量,我们需要使用以下命令:

sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -p udp --sport 53 -j ACCEPT

更多关于iptables选项参数的信息,请参考以下系统参考手册:

  • iptables(T0)
  • iptables-extensions(man iptables-extensions)。

现在,我们已经准备好保存iptables配置。

步骤 4 -保存配置

要保存当前iptables配置,我们必须运行以下命令:

sudo service iptables save

输出如下:

Figure 9.49 – Saving the iptables configuration

图 9.49 -保存 iptables 配置

我们还可以将当前配置转储到一个文件(例如iptables.config)中,以供以后使用,使用下面的命令:

sudo iptables-save -f iptables.config

-f(--file)选项参数指定要保存(备份)iptables配置的文件。 稍后我们可以使用以下命令恢复保存的iptables配置:

sudo iptables-restore ./iptables.config

在这里,我们可以指定到我们的iptables备份配置文件的任意路径。

iptables探索更复杂的规则和主题超出了本章的范围。 我们到目前为止提供的示例,以及iptables的理论介绍,应该是一个很好的开始,让大家探索更高级的配置。

另一方面,通常不鼓励使用iptables,特别是在最新的 Linux 发行版(如nftablesfirewalldufw中附带的新兴防火墙管理工具和框架中。 人们也多少接受了iptables存在性能和可伸缩性问题。

接下来,我们将看看nftables,一个由Netfilter 项目设计和开发的相对较新的框架,构建它是为了取代iptables

nftables 简介

nftablesiptables的继任人。 nftables是一个防火墙管理框架,支持包过滤网络地址转换(NAT)和各种包整形操作。 nftables与以前的包过滤工具相比,在功能、便捷性和性能方面都有显著的改进,例如:

  • 查找表代替规则的线性处理。
  • 规则是单独应用的,而不是处理一个完整的规则集。
  • IPv4 和 IPv6 协议的统一框架。
  • 没有特定于协议的扩展。

nftables背后的功能原则通常遵循前面关于防火墙网络链的部分中介绍的设计模式; 即netfilteriptables。 与iptables一样,nftables使用表来存储链。 每个链包含一组用于包过滤操作的规则。

nftables是 Debian 和 RHEL/CentOS 8 Linux 发行版中的默认包过滤框架,取代了旧的iptables(和相关)工具。 操作nftables配置的命令行界面是nft。 然而,有些用户更喜欢使用更友好的前端,比如firewalld。 (firewalld最近添加了nftables的后端支持。) 以 RHEL/CentOS 8 为例,其默认防火墙管理方案为firewalld

在本节中,我们将展示一些示例,说明如何使用nftables和相关的命令行实用程序来执行简单的防火墙配置任务。 为此,我们将使用 RHEL/CentOS 8 发行版,其中我们将禁用firewalld。 让我们快速浏览一下运行本节中的示例所需的准备步骤。

我们示例的先决条件

如果是 RHEL/CentOS 7 系统,nftables默认不安装。 你可以用以下命令安装它:

sudo yum install -y nftables

本节以 RHEL/CentOS 8 发行版为例进行说明。 要直接配置nftables,我们需要禁用firewalld,并可能禁用iptables(如果您运行了相关部分中的示例)。 在配置 iptables一节的开始部分显示了禁用firewalld的步骤。

另外,如果您启用了iptables,则需要使用以下命令停止和禁用相关服务:

sudo systemctl stop iptables
sudo systemctl disable iptables

接下来,我们需要启用和启动nftables:

sudo systemctl enable nftables
sudo systemctl start nftables

我们可以使用以下命令检查nftables的状态:

sudo systemctl status nftables

nftables的运行状态应该显示active:

Figure 9.50 – Checking the status of nftables

图 9.50 -检查 nftables 的状态

现在,我们准备配置nftables了。 让我们来看几个例子。

使用 nftables

ntftables/etc/sysconfig/nftables.conf加载其配置。 我们可以使用以下命令显示配置文件的内容:

sudo cat /etc/sysconfig/nftables.conf

默认的nftables配置在nftables.conf中没有活动的条目,除了一些注释:

Figure 9.51 – The default nftables configuration file

图 9.51 -默认的 nftables 配置文件

如注释所示,要更改nftables配置,我们有几个选项:

  • 直接编辑nftables.conf文件。
  • 手动编辑配置文件/etc/nftables/main.nft,然后取消注释nftables.conf中的相关行。
  • 使用nft命令行实用工具编辑规则,然后将当前配置转储到nftables.conf

不管采用哪种方法,我们都需要通过重新启动nftables服务来重新加载已更新的配置。 在本节中,我们将使用nft命令行示例来更改nftables配置。 高级用户通常编写nft配置脚本,但最好先学习基本步骤。

显示当前配置中的所有规则:

sudo nft list ruleset

您的系统可能已经设置了一些默认规则。 在继续下一步之前,您可以选择对相关配置(例如,/etc/sysconfig/nftables.conf/etc/nftables/main.nft)进行备份。

下面的命令将刷新所有已经存在的规则:

sudo nft flush ruleset

此时,我们有一个空配置。 让我们设计一个简单的防火墙,它接受 SSH、HTTP 和 HTTPS 通信,阻止其他任何东西。

接受 SSH、HTTP 和 HTTPS 流量

首先,我们需要创建一个和一个。 下面的命令创建了一个名为packt_table的表:

sudo nft add table inet packt_table

接下来,我们将在packt_table中创建一个名为packt_chain的链:

sudo nft add chain inet packt_table packt_chain { type filter hook input priority 0 \; }

现在,我们可以开始向packt_chain添加规则了。 允许 SSH、HTTP 和 HTTPS 访问:

sudo nft add rule inet packt_table packt_chain tcp dport {ssh, http, https} accept

让我们同时启用 ICMP (ping):

sudo nft add rule inet packt_table packt_chain ip protocol icmp accept

最后,我们将reject一切:

sudo nft add rule inet packt_table packt_chain reject with icmp type port-unreachable

现在,让我们来看看我们的新配置:

sudo nft list ruleset

输出如下:

Figure 9.52 – A simple firewall configuration with nftables

图 9.52 -带有 nftables 的简单防火墙配置

输出建议为我们的输入链(packt_chain)设置以下:

  • 允许目的端口2280443(tcp dport { 22, 80, 443 } accept)TCP 流量。
  • 允许ping请求(ip protocol icmp accept)。
  • 拒绝一切 else(meta nfproto ipv4 reject)。

接下来,我们将当前配置保存为/etc/nftables/packt.nft:

sudo nft list ruleset | sudo tee /etc/nftables/packt.nft

最后,通过添加以下行,我们将当前的nftables配置指向/etc/sysconfig/nftables.conf文件中的/etc/nftables/packt.nft:

include "/etc/nftables/packt.nft"

我们将使用nano(或您选择的编辑器)来进行更改:

sudo nano /etc/sysconfig/nftables.conf

新的nftables.conf现在包含了对packt.nft配置的引用:

Figure 9.53 – Including the new configuration in nftables

图 9.53 -在 nftables 中包含新的配置

下面的命令重新加载新的nftables配置:

sudo systemctl restart nftables

在这个练习之后,您可以使用nft list ruleset命令的输出快速编写一个脚本来配置nftables。 事实上,我们刚刚使用了/etc/nftables/packt.nft配置文件。

至此,我们将结束对包过滤框架和相关命令行实用程序的研究。 它们使高级用户能够对底层网络链和规则的每个功能方面进行细粒度控制。 然而,一些 Linux 管理员可能会发现这些工具的使用令人难以应付,转而使用相对简单的防火墙管理工具。

接下来,我们将研究两个本地 Linux 防火墙管理工具,它们为配置和管理防火墙提供了更精简和用户友好的命令行界面。

使用防火墙管理器

防火墙管理器是具有防火墙安全规则的相对易于使用的配置界面的命令行实用程序。 通常,这些工具需要超级用户特权,它们是 Linux 系统管理员的重要资产。

在接下来的章节中,我们将介绍两个在当今 Linux 发行版中广泛使用的最常见的防火墙管理器:

  • firewalld:RHEL/CentOS 平台
  • ufw:在 Ubuntu/Debian 上

防火墙管理器与其他网络安全工具(如iptablesnetfilternftables)相似,其主要区别在于它们为防火墙安全提供了更精简的用户体验。 使用防火墙管理器的一个重要好处是,当您操作各种安全配置更改时,不必重新启动网络守护进程。

让我们从 RHEL/CentOS 的默认防火墙管理器firewalld开始。

使用 firewalld

firewalld是用于各种 Linux 发行版的默认防火墙管理工具,包括以下内容:

  • RHEL/CentOS 7(及更新版本)
  • OpenSUSE 15(及更新版本)
  • Fedora 18(及更新版本)

在 CentOS 上,如果没有firewalld,我们可以用下面的命令安装它:

sudo yum install -y firewalld

我们可能还需要在启动时使用以下命令启用firewalld守护进程:

sudo systemctl enable firewalld

在继续之前,让我们确保firewalld已启用:

systemctl status firewalld

状态应该是active (running),如下截图所示:

Figure 9.54 – Making sure firewalld is active

图 9.54 -确保防火墙处于激活状态

firewalld有一组命令行实用程序用于不同的任务:

  • firewall-cmd:firewalld的主要命令行工具
  • firewall-offline-cmd:用于在离线(未运行)时配置firewalld
  • firewall-config:图形用户界面工具,用于配置firewalld
  • firewall-applet:一个系统托盘应用,用于提供firewalld的基本信息(如运行状态、连接等)

在本节中,我们将查看一些使用firewall-cmd实用程序的实际示例。 对于任何其他实用程序,您可以参考相关的系统参考手册(如man firewall-config)以获得更多信息。

firewalld(与之相关的firewalld-cmd)使用与监视和控制网络包相关的几个关键概念:区域规则目标

区域是firewalld配置的顶层组织单元。 firewalld监控的网络报文如果匹配了该网络区域关联的网口或 IP 地址/掩码源,则该网络报文属于该网络区域。 下面的命令列出了预定义区域的名称:

sudo firewall-cmd --get-zones

该命令输出如下:

Figure 9.55 – The predefined zones in firewalld

图 9.55 -防火墙中预定义的区域

关于当前已配置的所有区域的详细信息,我们可以运行以下命令:

sudo firewall-cmd --list-all-zones

以下是相关输出的摘录:

Figure 9.56 – Listing firewalld zones with details

图 9.56 -详细列出防火墙区域

前面的输出说明了两个区域(trustedwork),每个区域都有自己的属性,下面将解释其中的一些属性。 与接口相关联的区域是,称为活动区域。 查询激活的 zone:

sudo firewall-cmd --get-active-zones

在我们的例子中,输出如下:

Figure 9.57 – The firewalld active zones

图 9.57 - firewaldactive 区域

接口表示连接到本地主机的网络适配器。 活动接口被分配到缺省区域或用户自定义区域。 一个接口不能加入多个安全区域。

是入方向的 IP 地址或地址范围,也可以分配到区域中。 单个源或多个重叠 IP 地址范围不能分配给多个安全区域。 这样做将导致未定义的行为,因为它将不清楚哪个规则优先于相关区域。

缺省情况下,firewalld将所有网络接口分配到public区域,不关联任何源。 而且,在默认情况下,public是唯一的活动区域,因此是默认区域。 显示默认的 zone:

sudo firewall-cmd --get-default-zone

默认输出如下:

Figure 9.58 – Displaying the default zone in firewalld

图 9.58 -在防火墙中显示默认区域

可选参数。 因此,对于每个数据包,将有一个区域与匹配的网络接口。 但是,不一定有匹配的的区域。 该范例将在匹配规则的评估顺序中发挥重要作用。 我们将在规则优先部分讨论相关主题。 但首先,让我们先熟悉一下firewalld规则

规则

firewalld配置中定义的规则rich规则表示控制与特定区域关联的数据包的配置设置。 通常,一个规则会根据一些标准来决定数据包是被接受还是被拒绝。

例如,要阻止public区域使用 ping (ICMP 协议),我们可以添加以下rich规则:

sudo firewall-cmd --zone=public --add-rich-rule='rule protocol value="icmp" reject'

相关输出如下:

Figure 9.59 – Disabling ICMP access with firewalld

图 9.59 -使用防火墙禁用 ICMP 访问

我们可以使用以下命令检索public区域信息:

sudo firewall-cmd --info-zone=public

richrules 属性反映更新后的配置:

Figure 9.60 – Getting the public zone configuration with firewalld

图 9.60 -使用防火墙获取公共区域配置

此时,我们的主机将不再响应 ping (ICMP)请求。 我们可以通过以下命令删除刚刚添加的规则:

sudo firewall-cmd --zone=public --remove-rich-rule='rule protocol value="icmp" reject'

或者,我们可以使用以下命令启用 ICMP 访问:

sudo firewall-cmd --zone=public --add-rich-rule='rule protocol value="icmp" accept'

请注意,没有firewall-cmd实用程序的--permanent选项所做的更改是暂时的,在系统或firewalld重启后不会持续。

区域没有定义或匹配rich规则时,firewalld使用区域目标控制报文的行为。 下面让我们来看看target

目标

当报文匹配特定的区域时,firewalld根据相应区域的rich规则控制报文的行为。 如果没有定义rich规则,或者没有rich规则与数据包匹配,则数据包的行为最终由区域关联的target决定。 可能的目标值如下:

  • ACCEPT:接收报文
  • REJECT:拒绝报文,返回拒绝应答
  • DROP:没有回复就丢弃数据包
  • default:遵循firewalld的默认行为

区域规则目标firewalld分析和处理数据包时使用的关键配置元素。 数据包使用区域进行匹配,然后使用规则目标进行操作。 由于区域-基于网络接口和 IP 地址/范围的双重特性,firewalld在计算匹配标准时遵循特定的顺序(或优先级)。 我们接下来再看这个。

规则优先级

让我们先定义术语。 我们将与接口相关联的区域称为接口区域。 与源相关联的区域称为源区域。 由于区域可以同时具有接口和源,因此一个区域可以作为接口区域、*源区域、*或两者兼有。

firewalld处理数据包的顺序如下:

  1. 查看对应的源区域。 最多将有一个这样的区域(因为源只能与单个区域关联)。 如果匹配,则按照区域关联的规则目标处理报文。 否则,下一步进行数据包分析。
  2. 查看对应的接口区域*。 恰好有一个这样的区域(总是)存在。 如果匹配,则根据区域的规则目标处理数据包。 否则,下一步将进行报文验证。*

*让我们假设默认目标为firewalld——它接受 ICMP 数据包,拒绝其他所有数据包。

从前面的验证工作流中可以得到的关键信息是,源区域优先于接口区域。 多区域firewalld配置的典型设计模式定义了以下区域:

  • 特权源区域:从选择的 IP 地址提升系统访问
  • 限制接口区域:限制其他所有人的访问

让我们使用firewall-cmd实用程序来探索一些潜在的有用示例。

显示防火墙中已开启的服务。

sudo firewall-cmd --list-services

使用默认配置,我们得到以下输出:

Figure 9.61 – Displaying the enabled services in firewalld

图 9.61 -显示防火墙中启用的服务

启用 HTTPS 访问(端口443):

sudo firewall-cmd --zone=public --add-service=https

要添加用户定义的服务或端口(例如8443),我们可以运行以下命令:

sudo firewall-cmd --zone=public --add-port=8443/tcp

下面的命令列出了防火墙中开放的端口:

sudo firewall-cmd --list-ports

在我们的例子中,输出如下:

Figure 9.62 – Displaying the enabled ports in firewalld

图 9.62 -在防火墙中显示已启用的端口

在没有--permanent选项的情况下调用firewall-cmd命令会导致在系统(或firewalld)重启后不会持续的瞬时更改。 要重新加载先前保存的firewalld(永久)配置,我们可以运行以下命令:

sudo firewall-cmd --reload

有关firewalld的更多信息,请参考相关系统参考(man firewalld)或https://www.firewalld.org

使用查

简单防火墙(ufw)是 Ubuntu 中的默认防火墙管理器。 ufwiptablesnetfilter提供了一个相对简单的管理框架,并为操作防火墙提供了一个易于使用的命令行界面。

让我们看几个使用ufw的例子。 请注意,ufw命令行实用程序需要超级用户特权。 下面的命令报告了ufw的状态:

sudo ufw status

缺省情况下,ufwinactive(未启用):

Figure 9.63 – Displaying the current status of ufw

图 9.63 -显示 ufw 的当前状态

我们可以使用以下命令启用ufw:

sudo ufw enable

当您启用防火墙或执行任何可能影响您访问系统的更改时,始终要小心。 默认情况下,当启用ufw时,将阻止除 ping (ICMP)请求外的所有传入访问。 如果你用 SSH 登录,当你试图启用ufw时,你可能会得到以下提示:

Figure 9.64 – Enabling ufw could disrupt existing connections

图 9.64 -启用 ufw 可能会中断现有的连接

为了安全起见,您可能想要通过按n(No)并在防火墙中启用 SSH 访问来中止上述操作:

sudo ufw allow ssh

如果已经启用 SSH 访问,则不添加相关的安全规则:

Figure 9.65 – Attempting to add an existing rule to ufw

图 9.65 -尝试添加一个现有的规则到 ufw

此时,您可以安全地启用ufw,而不必担心当前或现有的 SSH 连接会被删除。 启用ufw后,我们得到如下输出:

Figure 9.66 – Enabling ufw

图 9.66 -启用 ufw

查看防火墙的详细状态,可以使用如下命令:

sudo ufw status verbose

显示如下信息,说明 SSH(22/tcp)和 HTTP/HTTPS(80,443/tcp)访问已开启。

Figure 9.67 – The detailed status of ufw

图 9.67 - ufw 的详细状态

如我们所见,HTTP/HTTPS 访问是通过Nginx Full应用概要文件启用的。 该规则被 Nginx 安装自动添加到ufw中。 请注意,其他客户机或服务器应用也可能向ufw添加此类规则。 总是建议检查您的防火墙设置,以确保无意访问系统是不允许的。

我们可以用下面的命令列出当前的应用安全配置文件:

sudo ufw app list

在我们的例子中,输出如下:

Figure 9.68 – Listing application security profiles in ufw

图 9.68 -在 ufw 中列出应用安全配置文件

要删除特定服务(如 HTTP)的访问,可以运行以下命令:

sudo ufw deny http

输出显示添加了一个新规则*:*

*Figure 9.69 – Disabling HTTP access in ufw

图 9.69 -在 ufw 中禁用 HTTP 访问

随后的详细状态检查将显示对端口80/tcp的访问被拒绝。 然而,结果却有些复杂:

Figure 9.70 – Complex rules in ufw

图 9.70 - ufw 中复杂的规则

我们只在中突出显示了涉及 HTTP 访问的 IPv4 对等规则。 在我们的例子中,我们有两个控制 HTTP 访问的规则:

80,443/tcp (Nginx Full)  ALLOW IN  Anywhere
80/tcp                   DENY IN   Anywhere

通过只关注 HTTP,我们可以看到第一条规则允许从任何地方访问 HTTP。 第二个规则拒绝从任何地方访问 HTTP。 结果规则:HTTP允许从任何地方开始。 为什么? 因为符合标准的第一个规则获胜。 匹配相同标准(即从任何地方访问 80/tcp)的后续规则将被丢弃。

重要提示

总是把更具体的*(限制性)规则放在首位。 在添加或更改规则时,您可能需要删除旧条目或重新排列它们的顺序,以确保规则被适当地放置和评估。*

*在本例中,我们需要删除Nginx Full规则。 请记住,该规则还支持 HTTPS 访问(443/tcp),我们可能希望保留该规则。 为了以正确的顺序恢复规则,让我们先得到规则列表的numbered输出:

sudo ufw status numbered

输出结果如下:

Figure 9.71 – Numbered list of rules in ufw

图 9.71 - ufw 规则编号列表

这些规则的顺序是由序列号提示的。 接下来,我们将使用相应的规则 ID(1)删除Nginx Full规则:

sudo ufw delete 1

我们会得到一个提示来批准这个操作:

Figure 9.72 – Deleting a rule in ufw

图 9.72 -在 ufw 中删除一个规则

防火墙现在的状态如下:

Figure 9.73 – The firewall's status after removing the Nginx Full application profile in ufw

图 9.73 -在 ufw 中删除 Nginx Full 应用配置文件后防火墙的状态

同样,我们删除相应的 IPv6 配置文件Nginx Full (v6),并删除相应的 ID(3)。 请注意,规则列表已经在之前的ufw delete操作中重新创建:

sudo ufw delete 3

现在,它是安全的重新添加Nginx HTTPS配置文件到只有启用 HTTPS 访问(443/tcp):

sudo ufw allow 'Nginx HTTPS'

最终状态现在产生以下输出:

Figure 9.74 – More specific rules should go first in ufw

图 9.74 -在 ufw 中应该先使用更具体的规则

如我们所见,更具体的(限制性的)规则(80/tcp DENY)首先出现(仅针对 IPv4 突出显示)。 我们甚至可以允许Nginx Full配置文件,它将启用 HTTP 访问。 然而,相应的规则(80/tcp ALLOW)将被放在更具限制性的对应规则之后,因此被丢弃。

或者,我们可以使用insert选项在给定位置添加特定规则。 例如,下面的命令将80/tcp DENY规则放置在第二位置(如上图所示):

sudo ufw insert 2 deny http

让我们再看几个使用ufw的例子。 从特定的源地址范围(192.168.0.0/24)开启所有协议(any)的 SSH 访问(端口22):

sudo ufw allow from 192.168.0.0/24 to any port 22

启用ufw日志:

sudo ufw logging on

相应的日志痕迹通常在/var/log/syslog中:

grep -i ufw /var/log/syslog

下面的日志跟踪表明失败(UFW BLOCK)从源地址(SRC=172.16.191.1)到我们的目的地地址(DST=172.16.191.4),针对 HTTP 服务端口80(DPT=80),使用 TCP 协议(PROTO=TCP):

Figure 9.75 – Analyzing ufw logs

图 9.75 -分析 ufw 日志

禁用ufw日志记录功能。

sudo ufw logging off

下面的命令将ufw恢复为系统默认值:

sudo ufw reset

执行上述命令将导致删除所有规则并禁用ufw

有关ufw的更多信息,您可能希望在https://help.ubuntu.com/community/UFW中查看UFW 社区帮助或相关的系统参考(man ufw)。

与较低级别的包过滤实用程序(例如netfilteriptablesnftables)相比,防火墙管理工具(如ufwfirewalld)的使用可能对某些 Linux 管理员更有吸引力。 除了平台考虑之外,选择一种工具而不是另一种工具的一个理由是与脚本和自动化功能有关。 一些高级用户可能认为nft命令行实用程序是设计防火墙规则的首选工具,因为nftables提供了粒度控制。 其他用户可能倾向于使用iptables,特别是在旧的遗留平台上。 最后,这是一个选择或偏好的问题,因为所有这些工具都能够在大致相同的程度上配置和管理防火墙。

让我们以一些最后的考虑来结束本章。

总结

这一章的内容相当丰富,可能显得令人难以应付。 一个关键的要点应该是关注框架(模块)。 如果我们正在讨论防火墙,我们应该看看包过滤框架,如iptablesnetfilternftables。 对于访问控制,我们有 SELinux 和 AppArmor 等安全模块。 我们讨论了每种方法的优缺点。 关键的选择是在 AppArmor 和 SELinux 之间,这可能决定了 Linux 发行版。 其中一个可能比另一个更快,因为相关政府的努力悬而未决。 例如,选择 AppArmor 可以将主要的 Linux 发行版缩小到 Ubuntu、Debian 和 OpenSUSE。 反过来,发行版的选择将进一步决定可用的防火墙管理解决方案,等等。

掌握应用安全性框架和防火墙管理工具将帮助您以最小的努力保持系统的安全。 与任何典型的 Linux 系统管理任务一样,有许多方法可以保护您的系统。 我们希望您将在本章中介绍的探索性知识和工具的基础上,做出一个关于保持系统安全的平衡决策。

下一章将通过介绍灾难恢复、诊断和故障排除实践,进一步提高系统的安全性和保护。

问题

这里有一个关于本章中涉及到的一些基本概念的小测验:

  1. 列举至少两个在 Linux 中使用的 acm。
  2. 枚举 SELinux 安全上下文的字段。
  3. SELinux 中的是什么?
  4. 您能想到 SELinux 和 AppArmor 在执行安全策略方面的显著区别吗?
  5. 用于检索当前应用概要文件的 AppArmor 命令行实用程序是什么?
  6. 我们如何在enforcecomplain模式之间切换 AppArmor 应用配置文件?
  7. 在 Linux 内核网络堆栈中,您能想到多少条链?
  8. RHEL/CentOS 8 的默认防火墙管理解决方案是什么? Ubuntu 怎么样?
  9. 您能想到设计防火墙规则的最佳实践吗?
  10. 如果你必须选择一个包过滤框架,你会选择哪个? 为什么?

进一步阅读

有关本章所涵盖的主题,请参阅以下资料:

  • 掌握 Linux 安全加固-第二版Donald A. Tevaultpackagpublishing
  • Practical Linux Security Cookbook - Second EditionTajinder Kalsipackpublishing
  • Practical Linux Security (video)Tajinder KalsiPackt Publishing
  • Linux 防火墙:通过 nftables 和 Beyond 增强安全性-第 4 版Steve Suehringaddion - wesley Professional*************