精通-Linux-安全和加固-全-
精通 Linux 安全和加固(全)
原文:
zh.annas-archive.org/md5/FE09B081B50264BD581CF4C8AD742097
译者:飞龙
前言
在这本书中,我们将介绍适用于任何基于 Linux 的服务器或工作站的安全和加固技术。我们的目标是让坏人更难对您的系统进行恶意操作。
这本书是为谁准备的
我们的目标读者是一般的 Linux 管理员,无论他们是否专门从事 Linux 安全工作。我们提出的技术可以用于 Linux 服务器或 Linux 工作站。
我们假设我们的目标读者在 Linux 命令行上有一些实践经验,并且具备 Linux 基础知识。
这本书涵盖了什么
第一章,在虚拟环境中运行 Linux,概述了 IT 安全领域,并告知读者为什么学习 Linux 安全是一个不错的职业选择。我们还将介绍如何建立一个进行实践练习的实验室环境。我们还将展示如何建立一个虚拟实验室环境来进行实践练习。
第二章,保护用户账户,介绍了始终使用根用户账户的危险,并将介绍使用 sudo 的好处。然后我们将介绍如何锁定普通用户账户,并确保用户使用高质量的密码。
第三章,使用防火墙保护服务器,涉及使用各种类型的防火墙工具。
第四章,加密和 SSH 加固,确保重要信息——无论是静态还是传输中的——都受到适当的加密保护。对于传输中的数据,默认的 Secure Shell 配置并不安全,如果保持原样可能会导致安全漏洞。本章介绍了如何解决这个问题。
第五章,掌握自主访问控制,介绍了如何设置文件和目录的所有权和权限。我们还将介绍 SUID 和 SGID 对我们有什么作用,以及使用它们的安全影响。最后我们将介绍扩展文件属性。
第六章,访问控制列表和共享目录管理,解释了普通的 Linux 文件和目录权限设置并不是非常精细。通过访问控制列表,我们可以只允许特定人访问文件,或者允许多人以不同的权限访问文件。我们还将整合所学知识来管理一个共享目录给一个群组使用。
第七章,使用 SELinux 和 AppArmor 实施强制访问控制,讨论了 SELinux,这是包含在 Red Hat 类型的 Linux 发行版中的强制访问控制技术。我们将在这里简要介绍如何使用 SELinux 防止入侵者破坏系统。AppArmor 是另一种包含在 Ubuntu 和 Suse 类型的 Linux 发行版中的强制访问控制技术。我们将在这里简要介绍如何使用 AppArmor 防止入侵者破坏系统。
第八章,扫描、审计和加固,讨论了病毒对 Linux 用户来说还不是一个巨大的问题,但对 Windows 用户来说是。如果您的组织有 Windows 客户端访问 Linux 文件服务器,那么这一章就是为您准备的。您可以使用 auditd 来审计对文件、目录或系统调用的访问。它不会防止安全漏洞,但会让您知道是否有未经授权的人试图访问敏感资源。SCAP,即安全内容应用协议,是由国家标准与技术研究所制定的合规性框架。开源实现的 OpenSCAP 可以用来将一个硬化策略应用到 Linux 计算机上。
第九章,《漏洞扫描和入侵检测》,解释了如何扫描我们的系统,以查看我们是否遗漏了任何内容,因为我们已经学会了如何为最佳安全性配置我们的系统。我们还将快速查看入侵检测系统。
第十章,《忙碌蜜蜂的安全提示和技巧》,解释了由于你正在处理安全问题,我们知道你很忙碌。因此,本章向您介绍了一些快速提示和技巧,以帮助您更轻松地完成工作。
为了充分利用本书
为了充分利用本书,您不需要太多。但是,以下内容将非常有帮助:
-
对基本 Linux 命令和如何在 Linux 文件系统中导航有一定的了解。
-
对于诸如 less 和 grep 之类的工具有基本的了解。
-
熟悉命令行编辑工具,如 vim 或 nano。
-
对使用 systemctl 命令控制 systemd 服务有基本的了解。
对于硬件,您不需要任何花哨的东西。您只需要一台能够运行 64 位虚拟机的机器。因此,您可以使用几乎任何一台配备现代 Intel 或 AMD CPU 的主机机器。(这个规则的例外是 Intel Core i3 和 Core i5 CPU。尽管它们是 64 位 CPU,但它们缺乏运行 64 位虚拟机所需的硬件加速。具有讽刺意味的是,远远更老的 Intel Core 2 CPU 和 AMD Opteron CPU 可以正常工作。)对于内存,我建议至少 8GB。
您可以在主机上运行任何三种主要操作系统,因为我们将使用的虚拟化软件适用于 Windows、MacOS 和 Linux。
下载彩色图像
我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图像。您可以在这里下载:www.packtpub.com/sites/default/files/downloads/MasteringLinuxSecurityandHardening_ColorImages.pdf
。
使用的约定
本书中使用了许多文本约定。
CodeInText
:指示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。这是一个例子:“让我们使用getfacl
来查看acl_demo.txt
文件上是否已经设置了任何访问控制列表。”
代码块设置如下:
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?
release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/
$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
priority=1
任何命令行输入或输出都以以下方式编写:
[donnie@localhost ~]$ tar cJvf new_perm_dir_backup.tar.xz new_perm_dir/ --acls
new_perm_dir/
new_perm_dir/new_file.txt
[donnie@localhost ~]$
粗体:表示一个新术语、一个重要词或屏幕上看到的词。例如,菜单或对话框中的单词会以这样的方式出现在文本中。这是一个例子:“点击 Network 菜单项,并将 Attached to 设置从 NAT 更改为 Bridged Adapter。”
警告或重要提示会以这种方式出现。
提示和技巧会以这种方式出现。
联系我们
我们始终欢迎读者的反馈。
一般反馈:发送电子邮件至feedback@packtpub.com
,并在主题中提及书名。如果您对本书的任何方面有疑问,请发送电子邮件至questions@packtpub.com
与我们联系。
勘误:尽管我们已经非常小心地确保了内容的准确性,但错误是难免的。如果您在本书中发现了错误,我们将不胜感激,如果您能向我们报告。请访问www.packtpub.com/submit-errata,选择您的书,点击勘误提交表格链接,并输入详细信息。
盗版:如果您在互联网上发现我们作品的任何非法副本,我们将不胜感激,如果您能向我们提供位置地址或网站名称。请通过copyright@packtpub.com
与我们联系,并附上材料链接。
如果您有兴趣成为一名作者:如果您在某个专业领域有专长,并且有兴趣撰写或为一本书做出贡献,请访问authors.packtpub.com。
评论
请留下评论。当您阅读并使用了这本书之后,为什么不在购买书籍的网站上留下评论呢?潜在的读者可以看到并使用您的客观意见来做出购买决定,我们在 Packt 可以了解您对我们产品的看法,而我们的作者也可以看到您对他们书籍的反馈。谢谢!
有关 Packt 的更多信息,请访问packtpub.com。
第一章:在虚拟环境中运行 Linux
所以,你可能会问自己,“为什么我需要学习 Linux 安全?Linux 不是已经很安全了吗?毕竟,它不是 Windows。”但事实是,有很多原因。
事实上,Linux 在安全方面确实比 Windows 有一些优势。这些包括:
-
与 Windows 不同,Linux 是从头开始设计的多用户操作系统。因此,在 Linux 系统上用户安全性往往会更好一些。
-
Linux 在管理用户和非特权用户之间提供了更好的分离。这使得入侵者更难一些,也使得用户更难意外地用一些恶意软件感染 Linux 机器。
-
Linux 比 Windows 更抵抗病毒和恶意软件感染。
-
某些 Linux 发行版带有内置机制,如 Red Hat 和 CentOS 中的 SELinux 和 Ubuntu 中的 AppArmor,可以防止入侵者控制系统。
-
Linux 是自由开源软件。这使得任何有技能的人都可以审计 Linux 代码以寻找漏洞或后门。
但即使有这些优势,Linux 也和人类创造的其他一切一样,不是完美的。
本章将涵盖的主题包括:
-
每个 Linux 管理员都需要了解 Linux 安全
-
威胁环境的一些内容,以及攻击者如何有时能够侵入 Linux 系统的一些例子
-
跟进 IT 安全新闻的资源
-
如何在 VirtualBox 上设置 Ubuntu Server 和 CentOS 虚拟机,以及如何在 CentOS 虚拟机中安装 EPEL 存储库
-
如何创建虚拟机快照
-
如何在 Windows 主机上安装 Cygwin,以便 Windows 用户可以从他们的 Windows 主机连接到虚拟机
威胁环境
如果你在过去几年一直关注 IT 技术新闻,你可能至少看过一些关于攻击者如何侵入 Linux 服务器的文章。例如,虽然 Linux 不太容易受到病毒感染,但已经有几起攻击者在 Linux 服务器上种植其他类型的恶意软件的案例。这些案例包括:
-
僵尸网络恶意软件:它会导致服务器加入由远程攻击者控制的僵尸网络。其中一个更著名的案例涉及将 Linux 服务器加入了对其他网络发动拒绝服务攻击的僵尸网络。
-
勒索软件:它旨在加密用户数据,直到服务器所有者支付赎金。但即使支付了赎金,也不能保证数据能够恢复。
-
加密货币挖矿软件:它会导致服务器的 CPU 额外努力工作并消耗更多能量。被挖掘的加密货币会进入种植软件的攻击者的账户。
当然,也有很多不涉及恶意软件的侵犯,比如攻击者找到了窃取用户凭据、信用卡数据或其他敏感信息的方法。
一些安全漏洞是因为纯粹的疏忽。这是一个例子,一个粗心的 Adobe 管理员将公司的私人安全密钥放在了公共安全博客上:www.theinquirer.net/inquirer/news/3018010/adobe-stupidly-posts-private-pgp-key-on-its-security-blog
。
那么,这是如何发生的呢?
无论你运行 Linux、Windows 还是其他系统,安全漏洞的原因通常是相同的。它们可能是操作系统中的安全漏洞,或者是运行在该操作系统上的应用程序中的安全漏洞。通常情况下,一个与漏洞相关的安全漏洞本可以通过管理员及时应用安全更新来防止。
另一个重要问题是配置不良的服务器。Linux 服务器的标准开箱即用配置实际上是相当不安全的,可能会引起一系列问题。配置不良的服务器的一个原因只是缺乏受过适当培训的人员来安全地管理 Linux 服务器。(当然,这对本书的读者来说是个好消息,因为相信我,IT 安全工作是不缺乏高薪的。)
在我们阅读本书的过程中,我们将看到如何以正确的方式做生意,使我们的服务器尽可能安全。
跟上安全新闻
如果您从事 IT 业务,即使您不是安全管理员,您也希望跟上最新的安全新闻。在互联网时代,这很容易做到。
首先,有很多专门从事网络安全新闻的网站。例如Packet Storm Security和The Hacker News。定期的技术新闻网站和 Linux 新闻网站,如The INQUIRER,The Register,ZDNet和LXer也会报道网络安全漏洞。如果您更喜欢观看视频而不是阅读,您会发现很多优秀的 YouTube 频道,如BeginLinux Guru。
最后,无论您使用哪个 Linux 发行版,请务必关注您的 Linux 发行版的新闻和当前文档。发行版维护者应该有一种方式来让您知道如果他们产品中出现了安全问题。
安全新闻网站的链接如下:
-
Packet Storm Security:
packetstormsecurity.com/
-
The Hacker News:
thehackernews.com/
一般技术新闻网站的链接如下:
-
The INQUIRER:
www.theinquirer.net/
-
The Register:
www.theregister.co.uk/
-
ZDNet:
www.zdnet.com/
您还可以查看一些一般的 Linux 学习资源。Linux 新闻网站:
-
LXer:
lxer.com/
-
BeginLinux Guru在 YouTube 上:
www.youtube.com/channel/UC88eard_2sz89an6unmlbeA
(完全披露:我是BeginLinux Guru。)
在阅读本书时要记住的一件事是,您将永远不会看到完全、100%安全的操作系统,它将安装在从不开机的计算机上。
VirtualBox 和 Cygwin 简介
每当我写作或教学时,我都会尽力不让学生失眠。在整本书中,您会看到一些理论,但我主要喜欢提供好的实用信息。还会有很多逐步实践的实验。
做实验的最佳方式是使用 Linux 虚拟机。我们将做的大部分工作都适用于任何 Linux 发行版,但我们也会做一些特定于 Red Hat Enterprise Linux 或 Ubuntu Linux 的事情。(Red Hat Enterprise Linux 是企业使用最广泛的,而 Ubuntu 在云部署中最受欢迎。)
红帽是一家价值十亿美元的公司,所以毫无疑问他们在 Linux 市场上的地位。但是,由于 Ubuntu Server 是免费的,我们不能仅仅根据其母公司的价值来判断其受欢迎程度。事实是,Ubuntu Server 是最广泛使用的 Linux 发行版,用于部署基于云的应用程序。
有关详情,请参阅:www.zdnet.com/article/ubuntu-linux-continues-to-dominate-openstack-and-other-clouds/
。
由于 Red Hat 是收费产品,我们将使用由 Red Hat 源代码构建并免费的 CentOS 7 来替代。您可以使用几种不同的虚拟化平台,但我自己的首选是 VirtualBox。
VirtualBox 适用于 Windows、Linux 和 Mac 主机,并且对所有这些主机都是免费的。它具有其他平台上需要付费的功能,例如创建虚拟机快照的能力。
我们将要做的一些实验将要求您模拟从主机机器到远程 Linux 服务器的连接。如果您的主机机器是 Linux 或 Mac 机器,您只需打开终端并使用内置的安全外壳工具。如果您的主机机器运行 Windows,则需要安装某种 Bash 外壳,我们将通过安装 Cygwin 来完成。
在 VirtualBox 中安装虚拟机
对于那些从未使用过 VirtualBox 的人,以下是一个快速入门指南:
-
下载并安装 VirtualBox 和 VirtualBox 扩展包。您可以从以下网址获取:
www.virtualbox.org/
。 -
下载 Ubuntu Server 和 CentOS 7 的安装
.iso
文件。您可以从以下网址获取:www.ubuntu.com/
和www.centos.org/
。 -
启动 VirtualBox 并单击屏幕顶部的新图标。在要求的位置填写信息。将虚拟驱动器大小增加到 20 GB,但将其他所有设置保持为默认设置:
- 启动新的虚拟机。单击对话框框的左下角的文件夹图标,并导航到您下载的
.iso
文件存储的目录。选择以下屏幕截图中显示的 Ubuntu.iso
文件或 CentOS.iso
文件中的一个:
-
单击对话框框上的“开始”按钮以开始安装操作系统。请注意,对于 Ubuntu Server,您将不会安装桌面界面。对于 CentOS 虚拟机,选择 KDE 桌面或 Gnome 桌面,如您所需。(我们将至少进行一个需要 CentOS 机器桌面界面的练习。)
-
对另一个 Linux 发行版重复该过程。
-
通过输入以下内容更新 Ubuntu 虚拟机:
sudo apt update
sudo apt dist-upgrade
- 暂时不要更新 CentOS 虚拟机,因为我们将在下一个练习中进行更新。
在安装 Ubuntu 时,您将被要求创建一个普通用户帐户和密码。它不会要求您创建根用户密码,而是会自动将您添加到 sudo 组,以便您具有管理员特权。
当您到达 CentOS 安装程序的用户帐户创建屏幕时,请确保为您自己的用户帐户选中“使此用户成为管理员”复选框,因为默认情况下未选中。它将为您提供创建根用户密码的机会,但这完全是可选的—事实上,我从来没有这样做。
CentOS 安装程序的用户帐户创建屏幕如下所示:
在 CentOS 虚拟机上的 EPEL 存储库
尽管 Ubuntu 软件包存储库几乎包含了您在本课程中所需的所有内容,但 CentOS 软件包存储库—我们可以说—是不足的。为了在 CentOS 实验中使用所需的软件包,您需要安装EPEL(企业 Linux 的额外软件包)存储库。(EPEL 项目由 Fedora 团队运行。)当您在 Red Hat 和 CentOS 系统上安装第三方存储库时,您还需要安装一个priorities
软件包,并编辑.repo
文件以为每个存储库设置适当的优先级。这将防止第三方存储库的软件包覆盖官方的 Red Hat 和 CentOS 软件包,如果它们恰好具有相同的名称。以下步骤将帮助您安装所需的软件包并编辑.repo
文件:
- 您需要安装 EPEL 的两个软件包在正常的 CentOS 存储库中。运行以下命令:
sudo yum install yum-plugin-priorities epel-release
- 安装完成后,转到
/etc/yum.repos.d
目录,并在您喜欢的文本编辑器中打开CentOS-Base.repo
文件。在base
、updates
和extras
部分的最后一行之后,添加一行priority=1
。在centosplus
部分的最后一行之后,添加一行priority=2
。保存文件并关闭编辑器。您编辑过的每个部分应该看起来像这样(除了适当的名称和优先级数字):
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?
release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/
$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
priority=1
-
打开
epel.repo
文件进行编辑。在epel
部分的最后一行之后,添加一行priority=10
。在每个剩余部分的最后一行之后,添加一行priority=11
。 -
更新系统,然后通过运行以下命令创建已安装和可用软件包的列表:
sudo yum upgrade
sudo yum list > yum_list.txt
为 VirtualBox 虚拟机配置网络
我们的一些培训场景将要求您模拟连接到远程服务器。您可以通过使用主机机器连接到虚拟机来实现这一点。当您首次在 VirtualBox 上创建虚拟机时,网络设置为 NAT 模式。为了从主机连接到虚拟机,您需要将虚拟机的网络适配器设置为桥接适配器模式。以下是您可以执行此操作的方法:
-
关闭您已经创建的任何虚拟机。
-
在 VirtualBox 管理器屏幕上,打开虚拟机的设置对话框。
-
单击网络菜单项,并将附加到设置从 NAT 更改为桥接适配器:
- 展开高级项目,并将混杂模式设置更改为允许全部:
- 重新启动虚拟机并设置其使用静态 IP 地址。
如果您从子网范围的高端分配静态 IP 地址,将更容易防止与从互联网网关分配的低号 IP 地址发生冲突。
使用 VirtualBox 创建虚拟机快照
与虚拟机一起工作的一个美妙之处是,如果出现问题,您可以创建快照并回滚到快照。使用 VirtualBox,这很容易做到。
- 在 VirtualBox 管理器屏幕的右上角,单击“快照”按钮:
- 在屏幕中间的左侧,您将看到一个相机图标。单击该图标以打开快照对话框。要么填写所需的快照名称,要么接受默认名称。可选地,您可以创建一个描述:
- 在对虚拟机进行更改后,您可以通过关闭虚拟机,然后右键单击快照名称并选择适当的菜单项来回滚到快照:
使用 Cygwin 连接到您的虚拟机
如果您的主机机器是 Linux 或 Mac 机器,您只需打开主机的终端并使用已经存在的工具连接到虚拟机。但是,如果您正在运行 Windows 机器,您需要安装某种 Bash shell 并使用其网络工具。Windows 10 Pro 现在带有由 Ubuntu 人员提供的 Bash shell,如果您愿意,可以使用它。但是,如果您没有 Windows 10 Pro,或者如果您更喜欢使用其他东西,您可以考虑 Cygwin。
Cygwin 是 Red Hat 公司的一个项目,是专为 Windows 构建的免费开源 Bash shell。它是免费的,而且易于安装。
在 Windows 主机上安装 Cygwin
以下是一个快速的 Cygwin 入门指南:
-
在主机机器的浏览器中,从以下网址下载适用于您的 Windows 版本的适当的
setup*.exe
文件:www.cygwin.com/
。 -
双击设置图标开始安装。在大多数情况下,只需接受默认值,直到您到达软件包选择屏幕。 (唯一的例外是您选择下载镜像的屏幕。)
-
在软件包选择屏幕的顶部,从“视图”菜单中选择“类别”:
- 展开“网络”类别:
- 向下滚动,直到看到 openssh 软件包。在“新”列下,点击“跳过”。(这将导致“跳过”位置出现版本号。)
- 在您选择了适当的软件包之后,您的屏幕应该是这样的:
-
在右下角,点击“下一步”。如果出现“解决依赖关系”屏幕,请也点击“下一步”。
-
保留您下载的安装文件,因为您稍后将使用它来安装更多软件包,或者更新 Cygwin。(当您打开 Cygwin 时,任何更新的软件包将显示在“视图”菜单上的“待处理”视图中。)
-
一旦您从 Windows“开始”菜单中打开 Cygwin,您可以根据需要调整其大小,并使用Ctrl + +或Ctrl + -键组合来调整字体大小:
总结
所以,我们已经很好地开始了我们的 Linux 安全和加固之旅。在本章中,我们看到了为什么了解如何保护和加固 Linux 系统与了解如何保护和加固 Windows 系统一样重要。我们提供了一些例子,说明了一个配置不良的 Linux 系统是如何被入侵的,并且我们提到了学习 Linux 安全对您的职业发展是有好处的。之后,我们看了如何使用 VirtualBox 和 Cygwin 设置虚拟化实验室环境。
在下一章中,我们将看看如何锁定用户账户,并确保错误的人永远不会获得管理员特权。到时见。
第二章:保护用户账户
管理用户是 IT 管理中更具挑战性的方面之一。您需要确保用户始终可以访问其内容,并且可以执行所需的任务来完成工作。您还需要确保用户的内容始终受到未经授权用户的保护,并且用户不能执行与其工作描述不符的任何任务。这是一个艰巨的任务,但我们的目标是表明这是可行的。
在本章中,我们将涵盖以下主题:
-
以 root 用户登录的危险
-
使用 sudo 的优势
-
如何为完整的管理用户和仅具有特定委派权限的用户设置 sudo 权限
-
使用 sudo 的高级技巧和技巧
-
锁定用户的主目录
-
强制执行强密码标准
-
设置和强制执行密码和帐户过期
-
防止暴力破解密码攻击
-
锁定用户帐户
-
设置安全横幅
以 root 用户登录的危险
Unix 和 Linux 操作系统相对于 Windows 的一个巨大优势是,Unix 和 Linux 更好地将特权管理帐户与普通用户帐户分开。事实上,旧版本的 Windows 容易受到安全问题的影响,例如随意病毒感染,一个常见的做法是设置具有管理权限的用户帐户,而没有新版本 Windows 中的用户访问控制的保护。(即使有用户访问控制,Windows 系统仍然会被感染,只是不太频繁。)在 Unix 和 Linux 中,更难以感染一个正确配置的系统。
您可能已经知道 Unix 或 Linux 系统上的超级管理员帐户是 root 帐户。如果您以 root 用户身份登录,您可以对该系统执行任何您想要执行的操作。因此,您可能会认为,“是的,这很方便,所以我会这样做。”但是,始终以 root 用户登录可能会带来一系列安全问题。考虑以下。以 root 用户登录可能会:
-
使您更容易意外执行导致系统损坏的操作
-
使其他人更容易执行导致系统损坏的操作
因此,如果您总是以 root 用户登录,甚至只是使 root 用户帐户容易访问,可以说您正在为攻击者和入侵者做很大一部分工作。此外,想象一下,如果您是一家大公司的 Linux 管理员,允许用户执行管理员任务的唯一方法是给他们所有的 root 密码。如果其中一个用户离开公司会发生什么?您不希望该人仍然有能力登录系统,因此您必须更改密码并将新密码分发给所有其他用户。而且,如果您只希望用户对某些任务具有管理员权限,而不是具有完整的 root 权限呢?
我们需要一种机制,允许用户执行管理任务,而不会冒着他们始终以 root 用户登录的风险,并且还允许用户仅具有他们真正需要执行某项工作的管理权限。在 Linux 和 Unix 中,我们通过 sudo 实用程序实现了这种机制。
使用 sudo 的优势
正确使用,sudo 实用程序可以极大地增强系统的安全性,并且可以使管理员的工作更加轻松。使用 sudo,您可以执行以下操作:
-
为某些用户分配完整的管理权限,同时为其他用户分配他们需要执行与其工作直接相关的任务所需的权限。
-
允许用户通过输入其自己的普通用户密码执行管理任务,以便您不必将 root 密码分发给每个人和他的兄弟。
-
增加入侵者进入系统的难度。如果您实施了 sudo 并禁用了 root 用户帐户,潜在的入侵者将不知道要攻击哪个帐户,因为他们不知道哪个帐户具有管理员权限。
-
创建 sudo 策略,即使网络中有 Unix、BSD 和 Linux 混合的机器,也可以在整个企业网络中部署。
-
提高您的审计能力,因为您将能够看到用户如何使用他们的管理员权限。
关于最后一条要点,考虑一下我 CentOS 7 虚拟机的secure
日志中的以下片段:
Sep 29 20:44:33 localhost sudo: donnie : TTY=pts/0 ; PWD=/home/donnie ; USER=root ; COMMAND=/bin/su -
Sep 29 20:44:34 localhost su: pam_unix(su-l:session): session opened for user root by donnie(uid=0)
Sep 29 20:50:39 localhost su: pam_unix(su-l:session): session closed for user root
您可以看到,我使用su -
登录到 root 命令提示符,然后退出登录。当我登录时,我做了一些需要 root 权限的事情,但没有记录下来。但记录下来的是我使用 sudo 做的事情。也就是说,因为这台机器上禁用了 root 帐户,我使用了我的 sudo 特权来让su -
为我工作。让我们看另一个片段,以展示更多关于这是如何工作的细节:
Sep 29 20:50:45 localhost sudo: donnie : TTY=pts/0 ; PWD=/home/donnie ; USER=root ; COMMAND=/bin/less /var/log/secure
Sep 29 20:55:30 localhost sudo: donnie : TTY=pts/0 ; PWD=/home/donnie ; USER=root ; COMMAND=/sbin/fdisk -l
Sep 29 20:55:40 localhost sudo: donnie : TTY=pts/0 ; PWD=/home/donnie ; USER=root ; COMMAND=/bin/yum upgrade
Sep 29 20:59:35 localhost sudo: donnie : TTY=tty1 ; PWD=/home/donnie ; USER=root ; COMMAND=/bin/systemctl status sshd
Sep 29 21:01:11 localhost sudo: donnie : TTY=tty1 ; PWD=/home/donnie ; USER=root ; COMMAND=/bin/less /var/log/secure
这一次,我使用我的 sudo 特权来打开一个日志文件,查看我的硬盘配置,执行系统更新,检查安全外壳守护程序的状态,再次查看日志文件。因此,如果您是我公司的安全管理员,您将能够看到我是否滥用了我的 sudo 权限。
现在,您可能会问,“有什么办法阻止一个人只是做一个 sudo su - 以防止他或她的不端行为被发现吗?” 这很容易。只是不要给人们去 root 命令提示符的权限。
为完整的管理员用户设置 sudo 权限
在我们看如何限制用户的操作之前,让我们首先看一下如何允许用户做任何事情,包括登录到 root 命令提示符。有几种方法可以做到这一点。
方法 1 - 将用户添加到预定义的管理员组
第一种方法,也是最简单的方法,是将用户添加到预定义的管理员组,然后,如果尚未完成,配置 sudo 策略以允许该组完成其工作。这很简单,只是不同的 Linux 发行版系列使用不同的管理员组。
在 Unix、BSD 和大多数 Linux 系统上,您可以将用户添加到wheel
组中。 (红帽家族的成员,包括 CentOS,属于这个类别。) 当我在我的 CentOS 机器上执行groups
命令时,我得到了这个:
[donnie@localhost ~]$ groups
donnie wheel
[donnie@localhost ~]$
这表明我是wheel
组的成员。通过执行sudo visudo
,我将打开 sudo 策略文件。向下滚动,我们将看到赋予wheel
组强大权限的行:
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL
百分号表示我们正在使用一个组。三个 ALL 表示该组的成员可以在部署了此策略的网络中的任何计算机上,作为任何用户执行任何命令。唯一的小问题是组成员将被提示输入他们自己的普通用户帐户密码以执行 sudo 任务。再往下滚动一点,你会看到以下内容:
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
如果我们注释掉前面片段中的%wheel
行,并从此片段中的%wheel
行前面删除注释符号,那么wheel
组的成员将能够在不输入任何密码的情况下执行所有 sudo 任务。这是我真的不建议的事情,即使在家庭使用中也是如此。在商业环境中,允许人们拥有无密码 sudo 权限是绝对不可以的。
要将现有用户添加到wheel
组中,使用usermod
命令和-G
选项。您可能还想使用-a
选项,以防止将用户从其他组中删除。对于我们的示例,让我们添加 Maggie:
sudo usermod -a -G wheel maggie
您还可以在创建用户帐户时将其添加到wheel
组中。现在让我们为 Frank 做到这一点:
sudo useradd -G wheel frank
请注意,使用useradd
时,我假设我们正在使用红帽系列的操作系统,该操作系统具有预定义的默认设置来创建用户账户。对于使用wheel
组的非红帽类型的发行版,您需要重新配置默认设置或使用额外的选项开关来创建用户的主目录并分配正确的 shell。您的命令可能如下所示:
sudo useradd -G wheel -m -d /home/frank -s /bin/bash frank
对于 Debian 系列的成员,包括 Ubuntu,程序是相同的,只是您将使用sudo
组而不是wheel
组。 (考虑到 Debian 人一直以来都是与众不同的,这种情况似乎是合理的。)
这种技术会在以下情况下非常有用,即当您需要在 Rackspace、DigitalOcean 或 Vultr 等云服务上创建虚拟专用服务器时。当您登录到这些服务并最初创建虚拟机时,云服务将要求您以 root 用户身份登录到该虚拟机。(即使在 Ubuntu 上也会发生这种情况,尽管在进行本地安装 Ubuntu 时会禁用 root 用户帐户。)
在这种情况下,您首先要做的是为自己创建一个普通用户帐户,并为其提供完整的 sudo 权限。然后,退出 root 帐户并使用普通用户帐户重新登录。然后,您将需要使用以下命令禁用 root 帐户:
sudo passwd -l root
您还需要进行一些额外的配置来锁定安全外壳访问,但我们将在第四章中进行介绍,加密和 SSH 加固。
方法 2 - 在 sudo 策略文件中创建条目
好的,将用户添加到wheel
组或sudo
组对于只使用一个这两个管理组的单个计算机或部署 sudo 策略的网络非常有效。但是,如果您想要在既有红帽又有 Ubuntu 机器的网络上部署 sudo 策略,或者如果您不想去每台机器上添加用户到管理员组,那么只需在 sudo 策略文件中创建一个条目。您可以为单个用户创建条目,也可以创建用户别名。如果在您的 CentOS 虚拟机上执行sudo visudo
,您将看到一个已注释的用户别名示例:
# User_Alias ADMINS = jsmith, mikem
您可以取消注释此行并添加您自己的一组用户名,或者您可以只添加一个包含您自己用户别名的行。要为用户别名的成员提供完整的 sudo 权限,请添加另一行,看起来像这样:
ADMINS ALL=(ALL) ALL
还可以为单个用户添加visudo
条目,在非常特殊的情况下可能需要这样做。例如:
frank ALL=(ALL) ALL
但为了便于管理,最好选择用户组或用户别名。
sudo 策略文件是/etc/sudoers
文件。我总是犹豫告诉学生这一点,因为偶尔会有学生尝试在常规文本编辑器中编辑它。但这是行不通的,请不要尝试。请始终使用命令sudo visudo
编辑sudoers
。
为仅具有特定委派权限的用户设置 sudo
IT 安全哲学的一个基本原则是为网络用户提供足够的权限,以便他们完成工作,但不得超出此范围。因此,您希望尽可能少的人拥有完整的 sudo 权限。(如果启用了 root 用户帐户,则希望更少的人知道 root 密码。)您还希望根据其具体工作来委派权限给人员。备份管理员将需要执行备份任务,帮助台人员将需要执行用户管理任务,依此类推。使用 sudo,您可以委派这些权限,并禁止用户执行与其工作描述不符的任何其他管理工作。
解释这一点的最好方法是让您在 CentOS 虚拟机上打开visudo
。因此,继续启动 CentOS VM 并输入以下命令:
sudo visudo
与 Ubuntu 不同,CentOS 有一个完全注释和有文档的sudoers
文件。我已经向您展示了创建ADMIN
用户别名的行,您可以为其他目的创建其他用户别名。例如,您可以为备份管理员创建BACKUPADMINS
用户别名,为 Web 服务器管理员创建WEBADMINS
用户别名,或者任何其他您想要的。因此,您可以添加类似以下内容的行:
User_Alias SOFTWAREADMINS = vicky, cleopatra
这很好,除了 Vicky 和 Cleopatra 仍然无法做任何事情。您需要将一些职责分配给用户别名。
如果您查看稍后提到的示例用户别名,您将看到一个示例Command Aliases
列表。其中一个例子恰好是SOFTWARE
,其中包含管理员需要安装或删除软件或更新系统的命令。它被注释掉,就像所有其他示例命令别名一样,因此您需要在使用之前从行首删除井号符号:
Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum
现在,只需将SOFTWARE
命令别名分配给SOFTWAREADMINS
用户别名即可:
SOFTWAREADMINS ALL=(ALL) SOFTWARE
SOFTWAREADMINS
用户别名的成员 Vicky 和 Cleopatra 现在可以以 root 权限运行rpm
、up2date
和yum
命令。
在取消注释并将它们分配给用户、组或用户别名之后,除了一个预定义的命令别名都可以使用。唯一的例外是SERVICES
命令别名:
Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start, /usr/bin/systemctl stop, /usr/bin/systemctl reload, /usr/bin/systemctl restart, /usr/bin/systemctl status, /usr/bin/systemctl enable, /usr/bin/systemctl disable
SERVICES
别名的问题在于它还列出了systemctl
命令的不同子命令。sudo 的工作方式是,如果一个命令单独列出,那么分配的用户可以使用该命令的任何子命令、选项或参数。因此,在SOFTWARE
示例中,SOFTWARE
用户别名的成员可以运行如下命令:
sudo yum upgrade
但是,当命令在命令别名中列出时带有子命令、选项或参数,那么分配给命令别名的任何人都可以运行。在当前配置中,SERVICES
命令别名中的systemctl
命令就无法工作。为了了解原因,让我们将 Charlie 和 Lionel 设置为SERVICESADMINS
用户别名,然后取消注释SERVICES
命令别名,就像我们之前已经做过的那样:
User_Alias SERVICESADMINS = charlie, lionel
SERVICESADMINS ALL=(ALL) SERVICES
现在,看看当 Lionel 尝试检查 Secure Shell 服务的状态时会发生什么:
[lionel@centos-7 ~]$ sudo systemctl status sshd
[sudo] password for lionel:
Sorry, user lionel is not allowed to execute '/bin/systemctl status sshd' as root on centos-7.xyzwidgets.com.
[lionel@centos-7 ~]$
好吧,所以 Lionel 可以运行sudo systemctl status
,这几乎没有用,但他无法做任何有意义的事情,比如指定他想要检查的服务。这有点问题。有两种方法可以解决这个问题,但只有一种方法是您想要使用的。您可以删除所有systemctl
子命令,并使SERVICES
别名看起来像这样:
Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl
但是,如果这样做,Lionel 和 Charlie 也将能够关闭或重新启动系统,编辑服务文件,或将机器从一个 systemd 目标更改为另一个。这可能不是您想要的。因为systemctl
命令涵盖了许多不同的功能,您必须小心,不要允许委派用户访问太多这些功能。更好的解决方案是为每个systemctl
子命令添加通配符:
Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, /usr/bin/systemctl start *, /usr/bin/systemctl stop *, /usr/bin/systemctl reload *, /usr/bin/systemctl restart *, /usr/bin/systemctl status *, /usr/bin/systemctl enable *, /usr/bin/systemctl disable *
现在,Lionel 和 Charlie 可以执行此命令别名中列出的任何服务的systemctl
功能:
[lionel@centos-7 ~]$ sudo systemctl status sshd
[sudo] password for lionel:
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2017-09-30 18:11:22 EDT; 23min ago
Docs: man:sshd(8)
man:sshd_config(5)
Main PID: 13567 (sshd)
CGroup: /system.slice/sshd.service
└─13567 /usr/sbin/sshd -D
Sep 30 18:11:22 centos-7.xyzwidgets.com systemd[1]: Starting OpenSSH server daemon...
Sep 30 18:11:22 centos-7.xyzwidgets.com sshd[13567]: Server listening on 0.0.0.0 port 22.
Sep 30 18:11:22 centos-7.xyzwidgets.com sshd[13567]: Server listening on :: port 22.
Sep 30 18:11:22 centos-7.xyzwidgets.com systemd[1]: Started OpenSSH server daemon.
[lionel@centos-7 ~]$
请记住,您不仅限于使用用户别名和命令别名。您还可以将特权分配给 Linux 组或个别用户。您还可以将单个命令分配给用户别名、Linux 组或个别用户。例如:
katelyn ALL=(ALL) STORAGE
gunther ALL=(ALL) /sbin/fdisk -l
%backup_admins ALL=(ALL) BACKUP
Katelyn 现在可以执行STORAGE
命令别名中的所有命令,而 Gunther 只能使用fdisk
来查看分区表。backup_admins
Linux 组的成员可以执行BACKUP
命令别名中的命令。
我们将在这个主题中看到的最后一件事是主机别名示例,这些示例出现在用户别名示例之前:
# Host_Alias FILESERVERS = fs1, fs2
# Host_Alias MAILSERVERS = smtp, smtp2
每个主机别名由服务器主机名列表组成。这样可以让您在一台机器上创建一个sudoers
文件,并在整个网络上部署它。例如,您可以创建一个WEBSERVERS
主机别名,一个WEBADMINS
用户别名,以及一个WEBCOMMANDS
命令别名,并附带适当的命令。
你的配置看起来应该是这样的:
Host_Alias WEBSERVERS = webserver1, webserver2
User_Alias WEBADMINS = junior, kayla
Cmnd_Alias WEBCOMMANDS = /usr/bin/systemctl status httpd, /usr/bin/systemctl start httpd, /usr/bin/systemctl stop httpd, /usr/bin/systemctl restart httpd
WEBADMINS WEBSERVERS=(ALL) WEBCOMMANDS
现在,当用户在网络上的服务器上键入命令时,sudo 首先查看该服务器的主机名。如果用户被授权在该服务器上执行该命令,那么 sudo 允许它。否则,sudo 拒绝它。在中小型企业中,手动将主sudoers
文件复制到网络上的所有服务器可能会很好用。但是,在大型企业中,您需要简化和自动化这个过程。为此,您可以使用 Puppet、Chef 或 Ansible 等工具。 (这三种技术超出了本书的范围,但您可以在 Packt 网站上找到关于它们三者的大量书籍和视频课程。)
所有这些技术在您的 Ubuntu VM 上以及在 CentOS VM 上都可以使用。唯一的问题是,Ubuntu 没有预定义的命令别名,所以你必须自己输入它们。
无论如何,我知道你已经厌倦了阅读,所以让我们开始工作吧。
分配有限 sudo 特权的实践实验
在这个实验中,您将创建一些用户并为他们分配不同级别的特权。为了简化,我们将使用 CentOS 虚拟机。
- 登录到 CentOS 虚拟机,并为 Lionel、Katelyn 和 Maggie 创建用户帐户:
sudo useradd lionel
sudo ueradd katelyn
sudo useradd maggie
sudo passwd lionel
sudo passwd katelyn
sudo passwd maggie
- 打开
visudo
:
sudo visudo
找到STORAGE
命令别名,并从其前面删除注释符号。
- 在文件末尾添加以下行,使用制表符分隔列:
lionel ALL=(ALL) ALL
katelyn ALL=(ALL) /usr/bin/systemctl status sshd
maggie ALL=(ALL) STORAGE
保存文件并退出visudo
。
- 为了节省时间,我们将使用
su
来登录不同的用户账户。您不需要注销自己的帐户来执行这些步骤。首先,登录 Lionel 的帐户,并通过运行几个 root 级别的命令来验证他是否拥有完整的 sudo 特权:
su - lionel
sudo su -
exit
sudo systemctl status sshd
sudo fdisk -l
exit
- 这次,以 Katelyn 的身份登录,并尝试运行一些 root 级别的命令。(不过,如果它们不都起作用,也不要太失望。)
su - katelyn
sudo su -
sudo systemctl status sshd
sudo systemctl restart sshd
sudo fdisk -l
exit
-
最后,以 Maggie 的身份登录,并运行为 Katelyn 运行的相同一组命令。
-
请记住,尽管我们在这个实验中只有三个单独的用户,但你可以通过在用户别名或 Linux 组中设置它们来处理更多的用户。
由于 sudo 是一个很好的安全工具,你会认为每个人都会使用它,对吧?遗憾的是,情况并非如此。几乎每当你查看 Linux 教程网站或 Linux 教程 YouTube 频道时,你都会看到正在进行演示的人以 root 用户命令提示符登录。在某些情况下,我甚至看到远程登录云虚拟机时以 root 用户身份登录的人。现在,如果已经以 root 用户身份登录是一个坏主意,那么通过互联网以 root 用户身份登录就更糟糕了。无论如何,看到每个人都从 root 用户的 shell 进行教程演示让我非常疯狂。
尽管说了这么多,有一些事情在 sudo 中是行不通的。Bash shell 内部命令,比如cd
不能使用它,将内核值注入/proc
文件系统也不能使用它。对于这样的任务,一个人必须转到 root 命令提示符。尽管如此,确保只有绝对需要使用 root 用户命令提示符的用户才能访问它。
使用 sudo 的高级技巧和技巧
现在我们已经了解了设置良好的 sudo 配置的基础知识,我们面临一个悖论。也就是说,尽管 sudo 是一个安全工具,但你可以用它做的某些事情可能会使你的系统比以前更不安全。让我们看看如何避免这种情况。
sudo 计时器
默认情况下,sudo 计时器设置为 5 分钟。这意味着一旦用户执行了一个sudo
命令并输入了密码,他或她可以在 5 分钟内执行另一个sudo
命令,而无需再次输入密码。尽管这显然很方便,但如果用户离开他们的桌子时仍然保持命令终端打开,这也可能会有问题。如果 5 分钟计时器尚未到期,其他人可能会来执行一些根级任务。如果您的安全需求需要,您可以通过向sudoers
文件的Defaults
部分添加一行来轻松禁用此计时器。这样,用户每次运行sudo
命令时都必须输入他们的密码。您可以将此设置为所有用户的全局设置,也可以仅为某些个别用户设置。
禁用 sudo 计时器的实践实验
在本实验中,您将禁用 CentOS VM 上的 sudo 计时器。
-
登录到您用于上一个实验的相同的 CentOS 虚拟机。我们将使用您已经创建的用户帐户。
-
在您自己的用户帐户命令提示符下,输入以下命令:
sudo fdisk -l
sudo systemctl status sshd
sudo iptables -L
您会发现您只需要输入一次密码就可以执行所有三个命令。
- 使用以下命令打开
visudo
:
sudo visudo
在文件的Defaults
规范部分中,添加以下行:
Defaults timestamp_timeout = 0
保存文件并退出visudo
。
-
执行您在步骤 2中执行的命令。这一次,您会发现每次都需要输入密码。
-
打开
visudo
并修改您添加的行,使其看起来像这样:
Defaults:lionel timestamp_timeout = 0
保存文件并退出visudo
。
-
从您自己的帐户 shell 中,重复您在步骤 2中执行的命令。然后,以 Lionel 的身份登录并再次执行命令。
-
请注意,这个相同的过程也适用于 Ubuntu。
防止用户具有 root shell 访问权限
假设您想要为具有有限 sudo 特权的用户设置一个用户,但是您通过添加类似于以下内容的行来实现:
maggie ALL=(ALL) /bin/bash, /bin/zsh
很抱歉告诉您,您根本没有限制 Maggie 的访问权限。您实际上给了她 Bash shell 和 Zsh shell 的完全 sudo 特权。因此,请不要像这样向您的sudoers
添加行,因为这会给您带来麻烦。
防止用户使用 shell 转义
某些程序,特别是文本编辑器和分页器,具有方便的shell 转义功能。这允许用户在不必先退出程序的情况下运行 shell 命令。例如,在 Vi 和 Vim 编辑器的命令模式中,某人可以通过执行:!ls
来运行ls
命令。执行该命令将如下所示:
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
~
~
:!ls
输出将如下所示:
[donnie@localhost default]$ sudo vim useradd
[sudo] password for donnie:
grub nss useradd
Press ENTER or type command to continue
grub nss useradd
Press ENTER or type command to continue
现在,假设您希望 Frank 能够编辑sshd_config
文件,仅限于该文件。您可能会诱惑添加一行到您的 sudo 配置,看起来像这样:
frank ALL=(ALL) /bin/vim /etc/ssh/sshd_config
这看起来应该可以工作,对吧?但实际上不行,因为一旦 Frank 使用他的 sudo 特权打开了sshd_config
文件,他就可以使用 Vim 的 shell 转义功能执行其他根级命令,这将包括能够编辑其他配置文件。您可以通过让 Frank 使用sudoedit
而不是 vim 来解决这个问题:
frank ALL=(ALL) sudoedit /etc/ssh/sshd_config
sudoedit
没有 shell 转义功能,因此您可以安全地允许 Frank 使用它。
其他具有 shell 转义功能的程序包括以下内容:
-
emacs
-
less
-
view
-
more
防止用户使用其他危险程序
即使没有 shell 转义功能的某些程序,如果您给予用户无限制的使用特权,仍然可能会很危险。这些包括以下内容:
-
cat
-
cut
-
awk
-
sed
如果您必须授予某人 sudo 特权以使用其中一个程序,最好将其使用限制在特定文件中。这就引出了我们的下一个提示。
限制用户使用命令的操作
假设您创建了一个 sudo 规则,以便 Sylvester 可以使用systemctl
命令:
sylvester ALL=(ALL) /usr/bin/systemctl
这使得 Sylvester 可以充分利用systemctl
的功能。他可以控制守护进程,编辑服务文件,关闭或重启,以及systemctl
的其他功能。这可能不是你想要的。最好指定 Sylvester 被允许执行哪些systemctl
功能。假设你希望他只能控制安全外壳服务。你可以让这行看起来像这样:
sylvester ALL=(ALL) /usr/bin/systemctl * sshd
Sylvester 现在可以做所有他需要做的安全外壳服务的事情,但他不能关闭或重启系统,编辑服务文件,或更改 systemd 目标。但是,如果你希望 Sylvester 只能对安全外壳服务执行某些特定的操作呢?那么,你将不得不省略通配符,并指定你希望 Sylvester 执行的所有操作:
sylvester ALL=(ALL) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
现在,Sylvester 只能重新启动安全外壳服务或检查其状态。
在编写 sudo 策略时,你需要了解网络上不同 Linux 和 Unix 发行版之间的差异。例如,在 Red Hat 7 和 CentOS 7 系统上,systemctl
二进制文件位于/usr/bin
目录中。在 Debian/Ubuntu 系统上,它位于/bin
目录中。如果你必须向混合操作系统的大型企业网络部署sudoers
文件,你可以使用主机别名来确保服务器只允许执行适合其操作系统的命令。
此外,要注意一些系统服务在不同的 Linux 发行版上有不同的名称。在红帽和 CentOS 系统上,安全外壳服务是sshd
。在 Debian/Ubuntu 系统上,它只是普通的ssh
。
让用户以其他用户身份运行
在下面的这行中,(ALL)
表示 Sylvester 可以以任何用户身份运行systemctl
命令:
sylvester ALL=(ALL) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
这实际上给了 Sylvester 这些命令的 root 权限,因为 root 用户绝对是任何用户。如果需要的话,可以将(ALL)
更改为(root)
,以指定 Sylvester 只能以 root 用户身份运行这些命令:
sylvester ALL=(root) /usr/bin/systemctl status sshd, /usr/bin/systemctl restart sshd
好吧,可能没有太多意义,因为没有什么改变。Sylvester 以前对这些systemctl
命令拥有 root 权限,现在仍然拥有。但是,这个功能还有更多实际的用途。假设 Vicky 是数据库管理员,你希望她以database
用户身份运行:
vicky ALL=(database) /usr/local/sbin/some_database_script.sh
然后 Vicky 可以以database
用户的身份运行该命令,输入以下代码:
sudo -u database some_database_script.sh
这是一个你可能不经常使用的功能,但无论如何要记住。你永远不知道什么时候会派上用场。
好了,这就结束了我们对 sudo 的讨论。现在让我们把注意力转向确保我们普通用户的安全。
以红帽或 CentOS 的方式锁定用户的主目录
这是另一个领域,不同的 Linux 发行版家族之间的业务方式不同。正如我们将看到的,每个发行版家族都有不同的默认安全设置。监督不同 Linux 发行版混合环境的安全管理员需要考虑到这一点。
红帽企业 Linux 及其所有后代,如 CentOS,有一个美好的特点,就是它们的开箱即用安全性比其他任何 Linux 发行版都要好。这使得加固红帽类型系统变得更快更容易,因为很多工作已经完成。其中一个已经为我们完成的工作是锁定用户的主目录:
[donnie@localhost home]$ sudo useradd charlie
[sudo] password for donnie:
[donnie@localhost home]$
[donnie@localhost home]$ ls -l
total 0
drwx------. 2 charlie charlie 59 Oct 1 15:25 charlie
drwx------. 2 donnie donnie 79 Sep 27 00:24 donnie
drwx------. 2 frank frank 59 Oct 1 15:25 frank
[donnie@localhost home]$
在红帽类型系统上,默认情况下,useradd
实用程序创建权限设置为700
的用户主目录。这意味着只有拥有主目录的用户可以访问它。所有其他普通用户都被锁定了。我们可以通过查看/etc/login.defs
文件来了解原因。向文件底部滚动,你会看到:
CREATE_HOME yes
UMASK 077
login.defs
文件是两个文件之一,用于配置useradd
的默认设置。这个UMASK
行决定了在创建家目录时的权限值。红帽类型的发行版将其配置为077
值,这将从组和其他中删除所有权限。这个UMASK
行在所有 Linux 发行版的login.defs
文件中,但是红帽类型的发行版是唯一一个默认将UMASK
设置为如此严格值的发行版。非红帽类型的发行版通常将UMASK
值设置为022
,这将创建权限值为755
的家目录。这允许每个人进入其他人的家目录并访问彼此的文件。
以 Debian/Ubuntu 方式锁定用户的家目录
Debian 及其后代,如 Ubuntu,有两个用户创建实用程序:
-
Debian/Ubuntu 上的
useradd
-
Debian/Ubuntu 上的
adduser
Debian/Ubuntu 上的 useradd
useradd
实用程序是存在的,但是 Debian 和 Ubuntu 没有像 Red Hat 和 CentOS 那样方便的预配置默认设置。如果您在默认的 Debian/Ubuntu 机器上只是执行sudo useradd frank
,Frank 将没有家目录,并且将被分配错误的默认 shell。因此,在 Debian 或 Ubuntu 系统上使用useradd
创建用户帐户,命令看起来会像这样:
sudo useradd -m -d /home/frank -s /bin/bash frank
在这个命令中:
-
-m
创建家目录。 -
-d
指定家目录。 -
-s
指定 Frank 的默认 shell。(如果没有-s
,Debian/Ubuntu 将为 Frank 分配/bin/sh
shell。)
当您查看家目录时,您会发现它们是完全开放的,每个人都有执行和读取权限:
donnie@packt:/home$ ls -l
total 8
drwxr-xr-x 3 donnie donnie 4096 Oct 2 00:23 donnie
drwxr-xr-x 2 frank frank 4096 Oct 1 23:58 frank
donnie@packt:/home$
正如您所看到的,Frank 和我都可以进入对方的东西。(不,我不希望 Frank 进入我的东西。)每个用户都可以更改自己目录的权限,但是你的用户中有多少人知道如何做到这一点呢?因此,让我们自己来解决这个问题:
cd /home
sudo chmod 700 *
让我们看看现在有什么:
donnie@packt:/home$ ls -l
total 8
drwx------ 3 donnie donnie 4096 Oct 2 00:23 donnie
drwx------ 2 frank frank 4096 Oct 1 23:58 frank
donnie@packt:/home$
看起来好多了。
要更改家目录的默认权限设置,请打开/etc/login.defs
进行编辑。查找一行,上面写着:
UMASK 022
更改为:
UMASK 077
现在,新用户的家目录将在创建时被锁定,就像红帽一样。
Debian/Ubuntu 上的adduser
adduser
实用程序是一种交互式方式,可以使用单个命令创建用户帐户和密码,这是 Debian 系列 Linux 发行版独有的。大多数缺少的默认设置已经为adduser
设置好了。默认设置唯一的问题是它使用宽松的755
权限值创建用户家目录。幸运的是,这很容易更改。(我们马上就会看到如何更改。)
尽管adduser
对于仅仅创建用户帐户很方便,但它不像useradd
那样灵活,并且不适合在 shell 脚本中使用。adduser
能做的一件事是在创建帐户时自动加密用户的家目录。要使其工作,您首先必须安装ecryptfs-utils
软件包。因此,要为 Cleopatra 创建一个带加密家目录的帐户,您可以这样做:
sudo apt install ecryptfs-utils
donnie@ubuntu-steemnode:~$ sudo adduser --encrypt-home cleopatra
[sudo] password for donnie:
Adding user `cleopatra' ...
Adding new group `cleopatra' (1004) ...
Adding new user `cleopatra' (1004) with group `cleopatra' ...
Creating home directory `/home/cleopatra' ...
Setting up encryption ...
************************************************************************
YOU SHOULD RECORD YOUR MOUNT PASSPHRASE AND STORE IT IN A SAFE LOCATION.
ecryptfs-unwrap-passphrase ~/.ecryptfs/wrapped-passphrase
THIS WILL BE REQUIRED IF YOU NEED TO RECOVER YOUR DATA AT A LATER TIME.
************************************************************************
Done configuring.
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for cleopatra
Enter the new value, or press ENTER for the default
Full Name []: Cleopatra Tabby Cat
Room Number []: 1
Work Phone []: 555-5556
Home Phone []: 555-5555
Other []:
Is the information correct? [Y/n] Y
donnie@ubuntu-steemnode:~$
第一次 Cleopatra 登录时,她需要运行前面输出中提到的ecryptfs-unwrap-passphrase
命令。然后她需要把密码写下来并存放在安全的地方:
cleopatra@ubuntu-steemnode:~$ ecryptfs-unwrap-passphrase
Passphrase:
d2a6cf0c3e7e46fd856286c74ab7a412
cleopatra@ubuntu-steemnode:~$
当我们到达加密章节时,我们将更详细地研究整个加密过程。
配置 adduser 的实践实验
在这个实验中,我们将使用adduser
实用程序,这是 Debian/Ubuntu 系统特有的:
- 在您的 Ubuntu 虚拟机上,打开
/etc/adduser.conf
文件进行编辑。找到一行,上面写着:
DIR_MODE=0755
更改为:
DIR_MODE=0700
保存文件并退出文本编辑器。
- 安装
ecryptfs-utils
软件包:
sudo apt install ecryptfs-utils
- 为 Cleopatra 创建一个带加密家目录的用户帐户,然后查看结果:
sudo adduser --encrypt-home cleopatra
ls -l /home
- 以 Cleopatra 的身份登录并运行
ecryptfs-unwrap-passphrase
命令:
su - cleopatra
ecryptfs-unwrap-passphrase
exit
请注意,adduser
要求的一些信息是可选的,您可以只按Enter键输入这些项目。
强制执行强密码标准
您可能不会认为一个听起来无害的话题,比如强密码标准会如此具有争议性,但事实上是如此。您无疑已经听说过整个计算机生涯中的常识说法:
-
制作一定最小长度的密码
-
制作由大写字母、小写字母、数字和特殊字符组成的密码
-
确保密码不包含字典中找到的任何单词,也不基于用户自己的个人数据
-
强制用户定期更改他们的密码
但是,使用您喜欢的搜索引擎,您会发现不同的专家对这些标准的细节存在分歧。例如,您会看到关于密码是否应该每 30、60 或 90 天更改的分歧,关于密码是否需要包含所有四种类型的字符的分歧,甚至关于密码的最小长度应该是多少的分歧。
最有趣的争议来自于——所有地方中最有趣的争议。他现在说,我们应该使用长而又容易记住的口令。他还说,只有在被破坏后才应该更改它们。
比尔·伯尔是前国家标准与技术研究所的工程师,他创建了我之前概述的强密码标准,他分享了自己为什么现在否定自己的工作的想法。
参考:www.pcmag.com/news/355496/you-might-not-need-complex-alphanumeric-passwords-after-all
。
然而,尽管如此,现实是大多数组织仍然固守使用定期过期的复杂密码的想法,如果你无法说服他们改变想法,你就必须遵守他们的规定。而且,如果你使用传统密码,你确实希望它们足够强大,能够抵抗任何形式的密码攻击。所以现在,我们将看一下在 Linux 系统上强制执行强密码标准的机制。
我必须承认,我以前从未想过在 Linux 系统上尝试创建口令来替代密码。所以,我刚刚在我的 CentOS 虚拟机上尝试了一下,看看它是否有效。
我为我的黑白礼服猫玛吉创建了一个账户。对于她的密码,我输入了口令“我喜欢其他猫”。你可能会想,“哦,那太糟糕了。这不符合任何复杂性标准,而且使用了字典中的单词。这怎么安全?”但是,事实上,这是一个由空格分隔的短语,这使得它安全且非常难以暴力破解。
现在,在现实生活中,我永远不会创建一个表达我对猫的爱的口令,因为很容易发现我真的很爱猫。相反,我会选择一个关于我生活中更隐秘的部分的口令,除了我之外没有人知道。
无论如何,与密码相比,口令有两个优点。它们比传统密码更难破解,但对用户来说更容易记住。但是为了额外的安全性,不要创建关于每个人都知道的生活事实的口令。
安装和配置 pwquality
我们将使用pwquality
模块进行PAM(可插拔认证模块)的设置。这是一种较新的技术,已经取代了旧的cracklib
模块。在 Red Hat 7 或 CentOS 7 系统上,默认安装了pwquality
,即使进行了最小安装。如果你cd
进入/etc/pam.d
目录,你可以进行grep
操作,查看 PAM 配置文件是否已经设置好。retry=3
表示用户在登录系统时只有三次尝试输入密码的机会。
[donnie@localhost pam.d]$ grep 'pwquality' *
password-auth:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password-auth-ac:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
system-auth:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
system-auth-ac:password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
[donnie@localhost pam.d]$
对于你的 Ubuntu 系统,你需要自己安装pwquality
。你可以使用以下命令来安装:
sudo apt install libpam-pwquality
现在我们cd
进入/etc/pam.d
目录,并执行与之前相同的grep
命令。我们会看到安装libpam-pwquality
模块会自动更新 PAM 配置文件:
donnie@packt:/etc/pam.d$ grep 'pwquality' *
common-password:password requisite pam_pwquality.so retry=3
donnie@packt:/etc/pam.d$
对于两种操作系统,其余的步骤都是一样的,只需要编辑/etc/security/pwquality.conf
文件。当你在文本编辑器中打开这个文件时,你会发现所有内容都被注释掉了,这意味着没有密码复杂性标准生效。你还会发现它有很好的文档说明,因为每个设置都有自己的解释性注释。
你可以根据需要设置密码复杂性标准,只需取消相应行的注释并设置适当的值。让我们看看其中一个设置:
# Minimum acceptable size for the new password (plus one if
# credits are not disabled which is the default). (See pam_cracklib manual.)
# Cannot be set to lower value than 6.
# minlen = 8
最小长度设置是基于 credit 系统的。这意味着对于密码中的每一种不同类型的字符类,最小要求的密码长度将减少一个字符。例如,让我们将minlen
设置为19
,并尝试为 Katelyn 分配密码turkeylips
:
minlen = 19
[donnie@localhost ~]$ sudo passwd katelyn
Changing password for user katelyn.
New password:
BAD PASSWORD: The password is shorter than 18 characters
Retype new password:
[donnie@localhost ~]$
因为turkeylips
中的小写字符计为一个字符类的 credit,所以我们只需要有 18 个字符而不是 19 个。如果我们再试一次,使用TurkeyLips
,我们会得到:
[donnie@localhost ~]$ sudo passwd katelyn
Changing password for user katelyn.
New password:
BAD PASSWORD: The password is shorter than 17 characters
Retype new password:
[donnie@localhost ~]$
这一次,大写的T
和大写的L
计为第二种字符类,所以我们只需要密码中有 17 个字符。
在minlen
行的下面,你会看到 credit 行。假设你不希望小写字母计入 credit,你会找到这一行:
# lcredit = 1
此外,你需要将1
改为0
:
lcredit = 0
然后,尝试为 Katelyn 分配密码turkeylips
:
[donnie@localhost ~]$ sudo passwd katelyn
Changing password for user katelyn.
New password:
BAD PASSWORD: The password is shorter than 19 characters
Retype new password:
[donnie@localhost ~]$
这一次,pwquality
确实需要 19 个字符。如果我们将 credit 值设置为大于 1 的值,我们将得到同一类类型的多个字符的 credit,直到达到该值。
我们也可以将 credit 值设置为负数,以要求密码中包含一定数量的字符类型。我们有以下示例:
dcredit = -3
这将要求密码中至少有三个数字。然而,使用这个功能是一个非常糟糕的主意,因为试图破解密码的人很快就会发现你要求的模式,这将帮助攻击者更精确地发起攻击。如果你需要要求密码包含多种字符类型,最好使用minclass
参数。
# minclass = 3
它已经设置为 3,这将要求密码中包含来自三种不同类的字符。要使用这个值,你只需要删除注释符。
pwquality.conf
中的其余参数基本上都是以相同的方式工作,每个参数都有一个很好的注释来解释它的作用。
如果你使用 sudo 权限来设置其他人的密码,系统会抱怨如果你创建的密码不符合复杂性标准,但它会允许你这样做。如果一个普通用户试图在没有 sudo 权限的情况下更改自己的密码,系统将不允许设置不符合复杂性标准的密码。
设置密码复杂性标准的实践实验
在这个实验中,你可以根据需要使用 CentOS 或 Ubuntu 虚拟机。唯一的区别是你不需要为 CentOS 执行步骤 1:
- 仅适用于 Ubuntu,安装
libpam-pwquality
包:
sudo apt install libpam-pwquality
- 在您喜欢的文本编辑器中打开
/etc/security/pwquality.conf
文件。从minlen
行前面删除注释符号,并将值更改为19
。现在应该看起来像这样:
minlen = 19
保存文件并退出编辑器。
-
为 Goldie 创建一个用户帐户,并尝试为她分配密码,
turkeylips
,TurkeyLips
和Turkey93Lips
。注意每个警告消息的变化。 -
在
pwquality.conf
文件中,注释掉minlen
行。取消注释minclass
行和maxclassrepeat
行。将maxclassrepeat
值更改为5
。现在应该看起来像:
minclass = 3
maxclassrepeat = 5
保存文件并退出文本编辑器。
- 尝试为 Goldie 的帐户分配不符合您设置的复杂性标准的各种密码,并查看结果。
在您的 CentOS 机器上的/etc/login.defs
文件中,您会看到以下行:
PASS_MIN_LEN 5
据说这是设置最小密码长度,但实际上,pwquality
会覆盖它。因此,您可以将此值设置为任何值,它都不会起作用。
设置和执行密码和帐户到期
您绝对不希望未使用的用户帐户保持活动状态。曾经发生过管理员为临时使用设置用户帐户的情况,例如为会议设置用户帐户,然后在不再需要帐户后就忘记了它们。另一个例子是,如果您的公司雇佣的合同工合同在特定日期到期。允许这些帐户在临时员工离开公司后保持活动和可访问性将是一个巨大的安全问题。在这种情况下,您需要一种方法来确保在不再需要时不会忘记临时用户帐户。如果您的雇主认同用户应定期更改密码的传统智慧,那么您还需要确保这样做。
密码到期数据和帐户到期数据是两回事。它们可以分别设置,也可以一起设置。当某人的密码过期时,他或她可以更改密码,一切都会很好。如果有人的帐户到期,只有具有适当管理员权限的人才能解锁它。
要开始,请查看您自己帐户的到期日期。(请注意,您不需要 sudo 权限来查看您自己的数据,但您仍然需要指定您自己的用户名。)
donnie@packt:~$ chage -l donnie
[sudo] password for donnie:
Last password change : Oct 03, 2017
Password expires : never
Password inactive : never
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
donnie@packt:~$
您可以在这里看到没有设置到期日期。这里的一切都是根据出厂默认值设置的。除了明显的项目之外,这里是您看到的内容的详细说明:
-
密码无效:如果这被设置为一个正数,我的帐户在系统锁定我的帐户之前将有那么多天时间更改过期的密码。
-
密码更改之间的最少天数:因为这被设置为
0
,我可以随意更改我的密码。如果它被设置为一个正数,我必须在更改密码后等待那么多天才能再次更改密码。 -
密码更改之间的最大天数:这被设置为默认值
99999
,意味着我的密码永远不会过期。 -
密码到期前的天数警告:默认值为
7
,但当密码设置为永不过期时,这是毫无意义的。
使用chage
实用程序,您可以为其他用户设置密码和帐户到期数据,或者使用-l
选项查看到期数据。任何非特权用户都可以使用chage -l
而无需 sudo 来查看自己的数据。要设置数据或查看其他人的数据,您需要 sudo。我们稍后将更仔细地看看chage
。
在我们看如何更改到期日期之前,让我们首先看看默认设置存储在哪里。我们首先看看/etc/login.defs
文件。三行相关的行是:
PASS_MAX_DAYS 99999
PASS_MIN_DAYS 0
PASS_WARN_AGE 7
您可以编辑这些值以适应您组织的需求。例如,将PASS_MAX_DAYS
更改为30
的值将导致从那时起所有新用户密码的到期日期为 30 天。(顺便说一句,在login.defs
中设置默认密码到期日期对于 Red Hat 或 CentOS 和 Debian/Ubuntu 都适用。)
为 useradd 配置默认到期日期-仅适用于 Red Hat 或 CentOS
/etc/default/useradd
文件包含其余的默认设置。在这种情况下,我们将查看来自 CentOS 机器的设置。
Ubuntu 也有相同的useradd
配置文件,但它不起作用。无论您如何配置,Ubuntu 版本的useradd
都不会读取它。因此,关于此文件的说明仅适用于 Red Hat 或 CentOS。
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
EXPIRE=
行设置了新用户帐户的默认到期日期。默认情况下,没有默认到期日期。INACTIVE=-1
表示用户帐户在用户密码过期后不会自动锁定。如果我们将其设置为正数,那么任何新用户在帐户被锁定之前将有这么多天来更改过期密码。要更改useradd
文件中的默认值,您可以手动编辑文件,也可以使用useradd -D
和适当的选项开关来更改要更改的项目。例如,要设置默认到期日期为 2019 年 12 月 31 日,命令将是:
sudo useradd -D -e 2019-12-31
要查看新配置,您可以打开useradd
文件,也可以执行sudo useradd -D
:
[donnie@localhost ~]$ sudo useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=2019-12-31
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
[donnie@localhost ~]$
您现在已经设置了任何新创建的用户帐户都具有相同的到期日期。您也可以使用INACTIVE
设置或SHELL
设置来做同样的事情:
sudo useradd -D -f 5
sudo useradd -D -s /bin/zsh
[donnie@localhost ~]$ sudo useradd -D
GROUP=100
HOME=/home
INACTIVE=5
EXPIRE=2019-12-31
SHELL=/bin/zsh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
[donnie@localhost ~]$
现在,任何新创建的用户帐户都将具有 Zsh shell 设置为默认 shell,并且必须在五天内更改过期密码,以防止帐户被自动锁定。
useradd
不会执行任何安全检查,以确保您分配的默认 shell 已安装在系统上。在我们的情况下,Zsh 没有安装,但useradd
仍然允许您创建具有 Zsh 作为默认 shell 的帐户。
那么,这个useradd
配置功能在现实生活中有多有用呢?可能并不那么有用,除非您需要一次性创建大量具有相同设置的用户帐户。即使如此,精明的管理员也会使用 shell 脚本自动化该过程,而不是在此配置文件中搞来搞去。
使用 useradd 和 usermod 为每个帐户设置到期日期
您可能会发现在login.defs
中设置默认密码到期日期很有用,但您可能不会发现在useradd
配置文件中配置很有用。实际上,您想要创建所有用户帐户具有相同的帐户到期日期的几率有多大呢?在login.defs
中设置密码到期日期更有用,因为您只需说明您希望新密码在特定天数内到期,而不是让它们在特定日期到期。
很可能,您会根据您知道帐户将在特定日期不再需要的情况来为每个帐户设置帐户到期日期。您可以通过以下三种方式来实现这一点:
-
使用
useradd
命令和适当的选项开关来在创建帐户时设置到期日期。(如果您需要一次性创建大量帐户,并且它们具有相同的到期日期,您可以使用 shell 脚本自动化该过程。) -
使用
usermod
来修改现有帐户的到期日期。(usermod
的美妙之处在于它使用与useradd
相同的选项开关。) -
使用
chage
来修改现有帐户的到期日期。(这个命令使用完全不同的一组选项开关。)
您可以使用useradd
和usermod
来设置帐户到期日期,但不能用于设置密码到期日期。影响帐户到期日期的唯一两个选项开关是:
-
-e
:使用此选项为帐户设置到期日期,格式为 YYYY-MM-DD -
-f
:使用此选项设置用户密码过期后要锁定其帐户的天数
假设您想为 Charlie 创建一个帐户,该帐户将在 2020 年底到期。在红帽或 CentOS 机器上,您可以输入以下内容:
sudo useradd -e 2020-12-31 charlie
在非红帽或 CentOS 机器上,您需要添加选项开关来创建主目录并分配正确的默认 shell:
sudo useradd -m -d /home/charlie -s /bin/bash -e 2020-12-31 charlie
使用chage -l
验证您输入的内容:
donnie@ubuntu-steemnode:~$ sudo chage -l charlie
Last password change : Oct 06, 2017
Password expires : never
Password inactive : never
Account expires : Dec 31, 2020
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
donnie@ubuntu-steemnode:~$
现在,假设 Charlie 的合同已经延长,您需要将他的帐户到期日期更改为 2021 年 1 月底。您可以在任何 Linux 发行版上以相同的方式使用usermod
:
sudo usermod -e 2021-01-31 charlie
再次使用chage -l
验证一切是否正确:
donnie@ubuntu-steemnode:~$ sudo chage -l charlie
Last password change : Oct 06, 2017
Password expires : never
Password inactive : never
Account expires : Jan 31, 2021
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
donnie@ubuntu-steemnode:~$
可选地,您可以设置带有过期密码的帐户在被锁定之前的天数:
sudo usermod -f 5 charlie
但是,如果您现在这样做,您不会看到chage -l
输出中的任何差异,因为我们仍然没有为 Charlie 的密码设置到期日期。
使用chage
在每个帐户上设置到期日期
您只能使用chage
来修改现有帐户,并且您将用它来设置帐户到期或密码到期。以下是相关的选项开关:
-d |
如果您在某人的帐户上使用-d 0 选项,您将强制用户在下次登录时更改密码。 |
---|---|
-E |
这相当于useradd 或usermod 的小写-e 。它设置了用户帐户的到期日期。 |
-I |
这相当于useradd 或usermod 的-f 。它设置了带有过期密码的帐户在被锁定之前的天数。 |
-m |
这将设置更改密码之间的最小天数。换句话说,如果 Charlie 今天更改了密码,-m 5 选项将强制他等待五天才能再次更改密码。 |
-M |
这将设置密码过期前的最大天数。(但要注意,如果 Charlie 上次设置密码是 89 天前,使用-M 90 选项将导致他的密码明天过期,而不是 90 天后。) |
-W |
这将设置密码即将过期的警告天数。 |
您可以一次设置这些数据项中的一个,也可以一次设置它们全部。实际上,为了避免让您为每个单独的项目提供不同的演示而感到沮丧,让我们一次设置它们全部,除了-d 0
,然后我们将看看我们得到了什么:
sudo chage -E 2021-02-28 -I 4 -m 3 -M 90 -W 4 charlie
donnie@ubuntu-steemnode:~$ sudo chage -l charlie
Last password change : Oct 06, 2017
Password expires : Jan 04, 2018
Password inactive : Jan 08, 2018
Account expires : Feb 28, 2021
Minimum number of days between password change : 3
Maximum number of days between password change : 90
Number of days of warning before password expires : 4
donnie@ubuntu-steemnode:~$
所有到期日期现在已经设置。
对于我们的最后一个示例,假设您刚刚为 Samson 创建了一个新帐户,并且希望在他首次登录时强制他更改密码。有两种方法可以做到这一点。无论哪种方式,您都需要在初始设置密码后执行。我们有以下代码:
sudo chage -d 0 samson
or
sudo passwd -e samson
donnie@ubuntu-steemnode:~$ sudo chage -l samson
Last password change : password must be changed
Password expires : password must be changed
Password inactive : password must be changed
Account expires : never
Minimum number of days between password change : 0
Maximum number of days between password change : 99999
Number of days of warning before password expires : 7
donnie@ubuntu-steemnode:~$
设置帐户和密码到期日期的实践实验
在这个实验中,您将创建一对新的用户帐户,设置到期日期,并查看结果。您可以在 CentOS 或 Ubuntu 虚拟机上进行此实验。(唯一的区别将在useradd
命令上。)
- 为 Samson 创建一个带有到期日期为 2023 年 6 月 30 日的用户帐户,并查看结果。
对于 CentOS:
sudo useradd -e 2023-06-30 samson
sudo chage -l samson
对于 Ubuntu:
sudo useradd -m -d /home/samson -s /bin/bash -e 2023-06-30
sudo chage -l samson
- 使用
usermod
将 Samson 的帐户到期日期更改为 2023 年 7 月 31 日:
sudo usermod -e 2023-07-31
sudo chage -l samson
- 为 Samson 的帐户分配一个密码,然后强制他在首次登录时更改密码。以 Samson 的身份登录,更改他的密码,然后注销到您自己的帐户:
sudo passwd samson
sudo passwd -e samson
sudo chage -l samson
su - samson
exit
- 使用
chage
设置更改密码的等待期为 5 天,密码过期期限为 90 天,不活动期为 2 天,警告期为 5 天:
sudo chage -m 5 -M 90 -I 2 -W 5 samson
sudo chage -l samson
- 保留此帐户,因为您将在下一节的实验中使用它。
防止暴力密码攻击
令人惊讶的是,这又是一个引发一些争议的话题。我的意思是,没有人否认自动锁定遭受攻击的用户账户的智慧。有争议的部分涉及我们应该在锁定账户之前允许多少次失败的登录尝试。
回到计算机的石器时代,那是很久以前,我还有一头浓密的头发,早期的 Unix 操作系统只允许用户创建最多八个小写字母的密码。所以在那些日子里,早期人类可以通过坐在键盘前输入随机密码来暴力破解别人的密码。这就是当时开始有用户账户在只有三次登录尝试失败后被锁定的理念。如今,使用强密码,或者更好的是强大的口令,设置三次登录尝试失败后锁定账户将会有三个作用:
-
它会不必要地让用户感到沮丧
-
这会给帮助台人员带来额外的工作
-
如果一个账户真的遭受攻击,它会在你有机会收集有关攻击者的信息之前锁定该账户
将锁定值设置为更现实的值,比如 100 次登录尝试失败,仍然可以提供良好的安全性,同时也给你足够的时间来收集有关攻击者的信息。同样重要的是,你不会给用户和帮助台人员带来不必要的挫败感。
无论你的雇主允许你允许多少次登录尝试失败,你仍然需要知道如何设置它。所以,让我们开始吧。
配置 pam_tally2 PAM 模块
为了让这个魔法生效,我们将依赖我们的好朋友 PAM 模块。pam_tally2
模块已经安装在 CentOS 和 Ubuntu 上,但尚未配置。对于我们的两台虚拟机,我们将编辑/etc/pam.d/login
文件。配置它很容易,因为在pam_tally2
手册的底部有一个示例。
EXAMPLES
Add the following line to /etc/pam.d/login to lock the account after 4 failed logins. Root account will be locked as well. The accounts will be automatically unlocked after 20 minutes. The module does not have to be called in the account phase because the login calls pam_setcred(3) correctly.
auth required pam_securetty.so
auth required pam_tally2.so deny=4 even_deny_root unlock_time=1200
auth required pam_env.so
auth required pam_unix.so
auth required pam_nologin.so
account required pam_unix.so
password required pam_unix.so
session required pam_limits.so
session required pam_unix.so
session required pam_lastlog.so nowtmp
session optional pam_mail.so standard
在示例的第二行中,我们看到pam_tally2
设置为:
-
deny=4
: 这意味着在只有四次登录尝试失败后,遭受攻击的用户账户将被锁定 -
even_deny_root
: 这意味着即使是 root 用户账户在遭受攻击时也会被锁定 -
unlock_time=1200
: 在 1200 秒或 20 分钟后,账户将自动解锁
现在,如果你查看你的虚拟机上的实际login
文件,你会发现它们看起来并不像手册中的示例login
文件。没关系,我们仍然可以让它生效。
一旦你配置了login
文件并且有了登录失败,你会在/var/log
目录中看到一个新文件被创建。你可以使用pam_tally2
工具查看该文件中的信息。你也可以使用pam_tally2
手动解锁被锁定的账户,如果你不想等待超时期:
donnie@ubuntu-steemnode:~$ sudo pam_tally2
Login Failures Latest failure From
charlie 5 10/07/17 16:38:19
donnie@ubuntu-steemnode:~$ sudo pam_tally2 --user=charlie --reset
Login Failures Latest failure From
charlie 5 10/07/17 16:38:19
donnie@ubuntu-steemnode:~$ sudo pam_tally2
donnie@ubuntu-steemnode:~$
注意,当我对查理的账户进行重置后,再次查询时没有输出。
配置 pam_tally2 的实践实验
配置pam_tally2
非常容易,因为它只需要在/etc/pam.d/login
文件中添加一行。为了更方便,你可以直接从pam_tally2
手册中的示例中复制并粘贴该行。尽管我之前说过将失败登录次数增加到 100,但现在我们将该数字保持为4
。(我知道你不想要做 100 次失败登录来演示这个。)
- 在 CentOS 或 Ubuntu 虚拟机上,打开
/etc/pam.d/login
文件进行编辑。查找调用pam_securetty
模块的行。(在 Ubuntu 上大约在第 32 行,在 CentOS 上大约在第 2 行。)
在那一行下面,插入以下行:
auth required pam_tally2.so deny=4
even_deny_root unlock_time=1200
保存文件并退出编辑器。
-
在这一步中,你需要退出你自己的账户,因为
pam_tally2
不能与su
一起使用。所以,退出登录,然后故意使用错误的密码,尝试登录到你在上一个实验中创建的samson
账户。一直这样做,直到看到账户被锁定的消息。请注意,当deny
值设置为4
时,实际上需要五次失败的登录尝试才能锁定 Samson 的账户。 -
重新登录你自己的用户账户。运行这个命令并注意输出:
sudo pam_tally2
- 在这一步中,你将模拟自己是一个帮助台工作人员,Samson 刚打电话请求你解锁他的账户。在确认你确实在和真正的 Samson 交谈后,输入以下命令:
sudo pam_tally2 --user=samson --reset
sudo pam_tally2
- 现在你已经看到了这是如何工作的,打开
/etc/pam.d/login
文件进行编辑,并将deny=
参数从4
更改为100
,然后保存文件。(这将使您的配置在现代安全理念方面更加现实。)
锁定用户账户
好的,你刚刚看到了如何让 Linux 自动锁定遭受攻击的用户账户。有时候你也会想手动锁定用户账户。让我们看下面的例子:
-
当用户度假时,你希望确保没有人在他离开期间对他的账户进行操作
-
当用户因可疑活动而受到调查时
-
当用户离开公司时
关于最后一点,你可能会问自己:“为什么我们不能只删除那些不在这里工作的人的账户呢?”当然,你当然可以很容易地这样做。但在这样做之前,你需要查看当地的法律,确保自己不会陷入麻烦。例如,在美国,我们有萨班斯-奥克斯法,限制上市公司可以从他们的计算机中删除哪些文件。如果你删除了一个用户账户,以及该用户的主目录和邮件存储,你可能会触犯萨班斯-奥克斯法或者你自己国家的等同法律。
无论如何,有两个工具可以用来临时锁定用户账户:
-
使用
usermod
来锁定用户账户 -
使用
passwd
来锁定用户账户
使用 usermod 来锁定用户账户
假设 Katelyn 已经休产假,至少会离开几周。我们可以通过以下方式锁定她的账户:
sudo usermod -L katelyn
当你查看/etc/shadow
文件中 Katelyn 的条目时,你会看到她的密码哈希前面有一个感叹号,如下所示:
katelyn:!$6$uA5ecH1A$MZ6q5U.cyY2SRSJezV000AudP.ckXXndBNsXUdMI1vPO8aFmlLXcbGV25K5HSSaCv4RlDilwzlXq/hKvXRkpB/:17446:0:99999:7:::
这个感叹号阻止系统能够读取她的密码,从而有效地将她锁在了系统外。
要解锁她的账户,只需按照以下步骤:
sudo usermod -U katelyn
你会看到感叹号已经被移除,这样她现在可以登录她的账户了。
使用 passwd 来锁定用户账户
你也可以通过以下方式锁定 Katelyn 的账户:
sudo passwd -l katelyn
这与usermod -L
的功能相同,但方式略有不同。首先,passwd -l
会给出一些关于正在进行的操作的反馈,而usermod -L
则没有任何反馈。在 Ubuntu 上,反馈看起来像这样:
donnie@ubuntu-steemnode:~$ sudo passwd -l katelyn
[sudo] password for donnie:
passwd: password expiry information changed.
donnie@ubuntu-steemnode:~$
在 CentOS 上,反馈看起来像这样:
[donnie@localhost ~]$ sudo passwd -l katelyn
Locking password for user katelyn.
passwd: Success
[donnie@localhost ~]$
此外,在 CentOS 机器上,你会看到passwd -l
在密码哈希前面放置了两个感叹号,而不是一个。无论哪种方式,效果都是一样的。
要解锁 Katelyn 的账户,只需执行以下操作:
sudo passwd -u katelyn
在 Red Hat 或 CentOS 7 版本之前,usermod -U
只会移除passwd -l
在 shadow 文件密码哈希前面放置的一个感叹号,因此账户仍然被锁定。不过,这没什么大不了的,因为再次运行usermod -U
将移除第二个感叹号。
在 Red Hat 或 CentOS 7 中,已经修复了。passwd -l
命令仍然会在 shadow 文件中放置两个感叹号,但usermod -U
现在会将两者都删除。 (真是遗憾,因为这破坏了我喜欢给学生做的一个完美的演示。)
锁定根用户账户
云现在是大生意,现在很常见租用来自 Rackspace、DigitalOcean 或 Microsoft Azure 等公司的虚拟专用服务器。这些可以用于各种用途,如下:
-
你可以运行自己的网站,在那里安装自己的服务器软件,而不是让托管服务来做
-
你可以为其他人设置一个基于 Web 的应用
-
最近,我在 YouTube 上看到了一个加密挖矿频道的演示,演示了如何在租用的虚拟专用服务器上设置权益证明主节点
这些云服务的共同之处之一是,当你第一次设置你的账户并且提供商为你设置了一个虚拟机器时,他们会让你登录到根用户账户。(即使在 Ubuntu 上也会发生,尽管 Ubuntu 的本地安装上禁用了根账户。)
我知道有些人只是不断登录到这些基于云的服务器的根账户,却毫不在意,但这真的是一个可怕的想法。有僵尸网络,比如 Hail Mary 僵尸网络,不断扫描互联网上暴露 Secure Shell 端口的服务器。当僵尸网络找到一个时,它们会对该服务器的根用户账户进行暴力密码攻击。是的,有时候僵尸网络会成功闯入,特别是如果根账户设置了弱密码。
所以,当你设置基于云的服务器时,你要做的第一件事就是为自己创建一个普通用户账户,并为其设置完整的 sudo 权限。然后,退出根用户账户,登录到你的新账户,并执行以下操作:
sudo passwd -l root
我的意思是,真的,为什么要冒险让你的根账户受到威胁?
设置安全横幅
有一件你真的,真的不想要的事情就是有一个登录横幅,上面写着“欢迎来到我们的网络”。我这么说是因为很多年前,我参加了一门关于事件处理的 SANS 课程。我们的导师告诉我们一个故事,讲述了一家公司将一名涉嫌入侵网络的人告上法庭,结果案子被驳回。原因是什么?据称的入侵者说,“嗯,我看到了写着‘欢迎来到网络’的消息,所以我以为我真的是受欢迎的。” 是的,据说这就足以让案子被驳回。
几年后,我在我的一堂 Linux 管理员课上向学生们讲述了这个故事。一名学生说,“这毫无意义。我们所有人家门口都有欢迎地垫,但这并不意味着小偷可以随意进来。” 我不得不承认他说得有道理,现在我不得不怀疑这个故事的真实性。
无论如何,为了安全起见,你确实希望设置登录消息,明确表示只有授权用户才能访问系统。
使用 motd 文件
/etc/motd
文件将向通过 Secure Shell 登录系统的任何人显示消息横幅。在你的 CentOS 机器上,已经有一个空的motd
文件。在你的 Ubuntu 机器上,motd
文件不存在,但创建一个很简单。无论哪种方式,打开文件编辑器并创建你的消息。保存文件并通过 Secure Shell 远程登录进行测试。你应该会看到类似的东西:
maggie@192.168.0.100's password:
Last login: Sat Oct 7 20:51:09 2017
Warning: Authorized Users Only!
All others will be prosecuted.
[maggie@localhost ~]$
motd
代表每日消息。
使用问题文件
问题文件,也可以在/etc
目录中找到,在本地终端上显示一个消息,就在登录提示的上方。默认的问题文件只包含宏代码,会显示有关机器的信息。看下面的例子:
Ubuntu 16.04.3 LTS \n \l
或者,在 CentOS 机器上:
\S
Kernel \r on an \m
在 Ubuntu 机器上,横幅看起来会像这样:
在 CentOS 机器上,它看起来会像这样:
您可以在问题文件中放置安全消息,并在重新启动后显示出来:
实际上,在问题文件中放置安全消息真的有意义吗?如果您的服务器被妥善锁在一个带有受控访问的服务器房间里,那可能没有。
使用 issue.net 文件
别这样做。这是用于 telnet 登录的,任何在其服务器上启用 telnet 的人都是严重搞砸了。然而,出于某种奇怪的原因,issue.net
文件仍然挂在 /etc
目录中。
总结
在本章中,我们涵盖了很多内容,希望您找到了一些实用的建议。我们首先向您展示了始终以 root 用户身份登录的危险,以及您应该改用 sudo。除了向您展示 sudo 的基础用法之外,我们还研究了一些不错的 sudo 提示和技巧。然后,我们转向用户管理,看看如何锁定用户的主目录,如何强制执行强密码策略,以及如何强制执行帐户和密码过期策略。接着,我们讨论了一种防止暴力密码攻击的方法,如何手动锁定用户帐户,并设置安全横幅。
在下一章中,我们将看看如何使用各种防火墙实用程序。我会在那里见到你。
第三章:使用防火墙保护您的服务器
安全是最好分层处理的事情之一。我们称之为深度安全。因此,在任何公司网络上,您都会发现一个防火墙设备将互联网与非军事区(DMZ)分开,您的面向互联网的服务器就在其中。您还会在 DMZ 和内部局域网之间发现防火墙设备,并在每台独立的服务器和客户端上安装防火墙软件。我们希望尽可能地让入侵者难以到达我们网络中的最终目的地。
有趣的是,尽管所有主要的 Linux 发行版中,只有 SUSE 发行版和 Red Hat 类型的发行版已经设置并启用了防火墙。当您查看您的 Ubuntu 虚拟机时,您会发现它是完全开放的,就好像它在热烈欢迎任何潜在的入侵者一样。
由于本书的重点是加固我们的 Linux 服务器,我们将把本章重点放在我们服务器和客户端上的最后一道防线,即防火墙上。
在本章中,我们将涵盖:
-
iptables 的概述
-
Ubuntu 系统的 Uncomplicated Firewall
-
Red Hat 系统的 firewalld
-
nftables,一种更通用的防火墙系统
iptables 的概述
一个常见的误解是 iptables 是 Linux 防火墙的名称。实际上,Linux 防火墙的名称是netfilter,每个 Linux 发行版都内置了它。我们所知道的 iptables 只是我们可以用来管理 netfilter 的几个命令行实用程序之一。它最初是作为 Linux 内核 2.6 版本的一个功能引入的,所以它已经存在了很长时间。使用 iptables,您确实有一些优势:
-
它已经存在了足够长的时间,以至于大多数 Linux 管理员已经知道如何使用它
-
在 shell 脚本中使用 iptables 命令创建自己的自定义防火墙配置很容易
-
它具有很大的灵活性,您可以使用它来设置一个简单的端口过滤器、路由器或虚拟专用网络
-
它预装在几乎每个 Linux 发行版上,尽管大多数发行版不会预先配置它
-
它有很好的文档,可以在互联网上免费获得书籍长度的教程
但是,您可能知道,也有一些缺点:
-
IPv4 和 IPv6 需要它们自己特殊的 iptables 实现。因此,如果您的组织在迁移到 IPv6 的过程中仍需要运行 IPv4,您将不得不在每台服务器上配置两个防火墙,并为每个运行单独的守护程序(一个用于 IPv4,另一个用于 IPv6)。
-
如果您需要进行需要ebtables的 Mac 桥接,这是 iptables 的第三个组件,具有自己独特的语法。
-
arptables,iptables 的第四个组件,也需要自己的守护程序和语法。
-
每当您向正在运行的 iptables 防火墙添加规则时,整个 iptables 规则集都必须重新加载,这可能会对性能产生巨大影响。
直到最近,iptables 是每个 Linux 发行版上的默认防火墙管理器。大多数发行版仍然是如此,但 Red Hat Enterprise Linux 7 及其所有后代现在使用了一种称为firewalld的新技术。Ubuntu 自带Uncomplicated Firewall(ufw),这是一个易于使用的 iptables 前端。我们将在本章末尾探讨一种更新的技术nftables。
本章的目的是只看 iptables 的 IPv4 组件。(IPv6 组件的语法会非常相似。)
iptables 的基本用法
iptables 由四个规则表组成,每个表都有自己独特的目的:
-
过滤表:对于我们的服务器和客户端的基本保护,这是我们通常会使用的唯一表
-
NAT 表:网络地址转换(NAT)用于将公共互联网连接到私有网络
-
篡改表:这用于在网络数据包通过防火墙时进行更改
-
安全表:安全表仅用于安装了 SELinux 的系统
由于我们目前只对基本主机保护感兴趣,我们只会查看过滤器表。每个表由规则链组成,过滤器表由INPUT
,FORWARD
和OUTPUT
链组成。由于我们的 CentOS 7 机器使用 Red Hat 的 firewalld,我们将在我们的 Ubuntu 机器上查看这个。
虽然 Red Hat Enterprise Linux 7 及其后代确实已经安装了 iptables,但默认情况下已禁用,以便我们可以使用 firewalld。不可能同时运行 iptables 和 firewalld,因为它们是两种完全不兼容的完全不同的动物。因此,如果您需要在 Red Hat 7 系统上运行 iptables,可以这样做,但必须首先禁用 firewalld。
然而,如果您的组织仍在使用 Red Hat 或 CentOS 的第 6 版运行其网络,则您的机器仍在使用 iptables,因为 firewalld 对它们不可用。
我们将首先使用sudo iptables -L
命令查看当前配置:
donnie@ubuntu:~$ sudo iptables -L
[sudo] password for donnie:
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
命令:
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 的人希望您自己设置防火墙。我们将首先创建一个规则,允许来自我们的主机请求连接的服务器的传入数据包通过:
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
这是这个命令的分解:
-
-A INPUT
:-A
将规则放在指定链的末尾,本例中是INPUT
链。如果我们想要将规则放在链的开头,我们将使用-I
。 -
-m
:这调用了一个 iptables 模块。在这种情况下,我们调用conntrack
模块来跟踪连接状态。这个模块允许 iptables 确定我们的客户端是否与另一台机器建立了连接。 -
--ctstate
:我们的规则的ctstate
或连接状态部分正在寻找两件事。首先,它正在寻找客户端与服务器建立的连接。然后,它寻找从服务器返回的相关连接,以允许它连接到客户端。因此,如果用户使用 Web 浏览器连接到网站,此规则将允许来自 Web 服务器的数据包通过防火墙传递到用户的浏览器。 -
-j
:这代表jump。规则跳转到特定目标,本例中是ACCEPT
。(请不要问我是谁想出了这个术语。)因此,此规则将接受从客户端请求连接的服务器返回的数据包。
我们的新规则集如下:
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
,以便允许我们通过安全外壳进行连接。目前,我们不想打开更多的端口,所以我们将以阻止其他所有内容的规则结束:
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
sudo iptables -A INPUT -j DROP
这是分解:
-
-A INPUT
:与以前一样,我们希望使用-A
将此规则放在 INPUT 链的末尾。 -
-p tcp
:-p
表示此规则影响的协议。此规则影响 TCP 协议,其中安全外壳是其中的一部分。 -
--dport ssh
:当选项名称由多个字母组成时,我们需要在其前面加上两个破折号,而不是一个。--dport
选项指定我们希望此规则操作的目标端口。(请注意,我们也可以将规则的这部分列为--dport 22
,因为22
是 SSH 端口的编号。) -
-j ACCEPT
:将所有内容与-j ACCEPT
放在一起,我们就有了一个允许其他机器通过安全外壳连接到这台机器的规则。 -
最后的
DROP
规则悄悄地阻止所有未经特别允许的连接和数据包。
实际上,我们可以以两种方式编写最终的阻止规则:
-
sudo iptables -A INPUT -j DROP
:它会导致防火墙默默地阻止数据包,而不会向这些数据包的源发送任何通知。 -
sudo iptables -A INPUT -j REJECT
:它也会导致防火墙阻止数据包,但它还会向源发送有关数据包被阻止的消息。一般来说,最好使用DROP
,因为我们通常希望使恶意行为者更难以弄清楚我们的防火墙配置。
无论哪种方式,您总是希望将此规则放在链的末尾,因为在它之后的任何ALLOW
规则都将不起作用。
最后,我们对INPUT
链有了一个几乎完整的、可用的规则集:
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
链的第一个位置:
sudo iptables -I INPUT 1 -i lo -j ACCEPT
当我们查看我们的新规则集时,我们会看到一些非常奇怪的东西:
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
DROP all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
donnie@ubuntu:~$
嗯...
第一条规则和最后一条规则看起来是一样的,只是一个是DROP
,另一个是ACCEPT
。让我们再次使用-v
选项查看一下:
donnie@ubuntu:~$ sudo iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- lo any anywhere anywhere
393 25336 ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED
0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh
266 42422 DROP all -- any any anywhere anywhere
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 72 packets, 7924 bytes)
pkts bytes target prot opt in out source destination
donnie@ubuntu:~$
现在,我们看到lo
,即环回,出现在第一条规则的in
列下,any
出现在最后一条规则的in
列下。这一切看起来很不错,除了如果我们现在重新启动机器,规则将消失。我们需要做的最后一件事是使它们永久。有几种方法可以做到这一点,但在 Ubuntu 机器上最简单的方法是安装iptables-persistent
软件包:
sudo apt install iptables-persistent
在安装过程中,您将看到两个屏幕,询问您是否要保存当前的 iptables 规则集。第一个屏幕将用于 IPv4 规则,第二个屏幕将用于 IPv6 规则:
现在,您将在/etc/iptables
目录中看到两个新的规则文件:
donnie@ubuntu:~$ ls -l /etc/iptables*
total 8
-rw-r--r-- 1 root root 336 Oct 10 10:29 rules.v4
-rw-r--r-- 1 root root 183 Oct 10 10:29 rules.v6
donnie@ubuntu:~$
如果您现在重新启动机器,您会看到您的 iptables 规则仍然存在并生效。
基本 iptables 用法的实验室
您将在您的 Ubuntu 虚拟机上进行此实验室。
- 关闭您的 Ubuntu 虚拟机,并创建一个快照。
您将在下一节的实验室中回滚到此快照。
- 使用以下命令查看您的 iptables 规则,或者缺少规则:
sudo iptables -L
- 创建您需要的基本防火墙规则,允许安全外壳访问,但拒绝其他所有内容:
sudo iptables -A INPUT -m conntrack
--ctstate ESTABLISHED,RELATED
-j ACCEPT
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
sudo iptables -A INPUT -j DROP
- 使用以下命令查看结果:
sudo iptables -L
- 哎呀,看来您忘记了环回接口。在列表顶部为其添加一个规则:
sudo iptables -I INPUT 1 -i lo -j ACCEPT
- 使用这两个命令查看结果。注意每个输出之间的差异:
sudo iptables -L
sudo iptables -L -v
- 安装
iptables-persistent
软件包,并在提示时选择保存 IPv4 和 IPv6 规则:
sudo apt install iptables-persistent
-
重新启动虚拟机,并验证您的规则是否仍然有效。
-
实验室结束。
现在,我知道你在想,“哇,为了设置一个基本防火墙,要跳过这么多环节。”是的,你是对的。所以,请给我一点时间来摆脱我刚刚用 iptables 做的事情,我会向您展示 Ubuntu 人民是如何简化事情的。
您可以在这里了解如何在 Ubuntu 上使用 iptables 的全部信息:help.ubuntu.com/community/IptablesHowTo
。
Ubuntu 系统的 Uncomplicated Firewall
Uncomplicated Firewall 已经安装在您的 Ubuntu 机器上。它仍然使用 iptables 服务,但提供了一组大大简化的命令。执行一个简单的命令来启用它,您就有了一个良好的、预配置的防火墙。桌面机器上有一个图形化的前端,但由于我们正在学习服务器安全性,我们只会在这里介绍命令行实用程序。
ufw 的基本用法
ufw 默认处于禁用状态,因此您需要启用它:
donnie@ubuntu:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
donnie@ubuntu:~$
为了做到这一点,我从我信任的 OpenSUSE 工作站的终端远程登录到了虚拟机。它警告我说我的安全 Shell 连接可能会中断,但并没有发生。 (这可能是因为连接跟踪规则,也可能是我运气好。)我会留给你去运行sudo iptables -L
,因为 ufw 创建了一个非常庞大的默认规则集,这在这本书中是不可能显示的。
接下来,让我们添加一条规则,以便将来可以通过安全 Shell 进行远程连接:
sudo ufw allow 22/tcp
运行sudo iptables -L
,你会看到新规则出现在ufw-user-input
链中:
Chain ufw-user-input (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
在前面的sudo ufw allow 22/tcp
命令中,我们必须指定 TCP 协议,因为 TCP 是我们安全 Shell 所需的。我们也可以只通过不指定协议来为 TCP 和 UDP 打开端口。例如,如果你正在设置 DNS 服务器,你会希望为两种协议打开端口53
(你会看到端口53
的条目列为domain
端口):
sudo ufw allow 53
Chain ufw-user-input (1 references)
target prot opt source destination
ACCEPT tcp -- anywhere anywhere tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere tcp dpt:domain
ACCEPT udp -- anywhere anywhere udp dpt:domain
如果你运行sudo ip6tables -L
,你会看到 IPv6 的规则也被添加到了前面两个示例中。
基本 ufw 使用的实验。
你将在你的 Ubuntu 虚拟机的干净快照上进行这个实验:
-
关闭你的 Ubuntu 虚拟机并恢复快照。(你要这样做是为了摆脱你刚刚做的所有 iptables 的东西。)
-
当你重新启动虚拟机后,验证 iptables 规则现在已经消失:
sudo iptables -L
- 查看 ufw 的状态,启用它,并查看结果:
sudo ufw status
sudo ufw enable
sudo ufw status
sudo iptables -L
sudo ip6tables -L
- 打开
22/tcp
端口以允许安全 Shell 访问:
sudo ufw allow 22/tcp
sudo iptables -L
sudo ip6tables -L
- 这次,为 TCP 和 UDP 同时打开端口
53
:
sudo ufw allow 53
sudo iptables -L
sudo ip6tables -L
- 实验结束。
Red Hat 系统的 firewalld
到目前为止,我们已经看过 iptables,这是一个通用的防火墙管理系统,适用于所有的 Linux 发行版,以及 ufw,它只适用于 Ubuntu。接下来,我们将把注意力转向firewalld,它是专门针对 Red Hat Enterprise Linux 7 及其所有后代的。
与 Ubuntu 的 ufw 不同,firewalld 不仅仅是 iptables 的易于使用的前端。相反,它是一个全新的防火墙业务方式,并且与 iptables 不兼容。不过,要明白的是,iptables 仍然安装在 Red Hat 7 系列上,但没有启用,因为你不能同时启用 iptables 和 firewalld。如果你必须使用利用 iptables 的旧 shell 脚本,你可以禁用 firewalld 并启用 iptables。
iptables 和 firewalld 不兼容的原因是,iptables 将其规则存储在/etc/sysconfig
目录中的纯文本文件中,而 firewalld 将其规则文件存储在/etc/firewalld
目录和/usr/lib/firewalld
目录中的.xml
格式文件中。此外,iptables 不理解 firewalld 所理解的区域和服务的概念,规则本身的格式也完全不同。因此,即使你可以同时运行 iptables 和 firewalld,你最终只会混淆系统并破坏防火墙。
关键是,你可以在 Red Hat 或 CentOS 机器上运行 iptables 或 firewalld,但不能同时运行两者。
如果你在桌面机上运行 Red Hat 或 CentOS,你会在应用程序菜单中看到有一个 firewalld 的 GUI 前端。然而,在文本模式服务器上,你只能使用 firewalld 命令。出于某种原因,Red Hat 的人们没有为文本模式服务器创建一个类似 ncurses 的程序,就像他们在旧版本的 Red Hat 上为 iptables 配置所做的那样。
firewalld 的一个重要优势是它是动态管理的。这意味着你可以在不重启防火墙服务的情况下更改防火墙配置,并且不会中断到服务器的任何现有连接。
验证 firewalld 的状态
让我们首先验证 firewalld 的状态。有两种方法可以做到这一点。我们可以使用firewall-cmd
的--state
选项:
[donnie@localhost ~]$ sudo firewall-cmd --state
running
[donnie@localhost ~]$
或者,如果我们想要更详细的状态,我们可以像检查 systemd 机器上的任何其他守护程序一样检查守护程序:
[donnie@localhost ~]$ sudo systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2017-10-13 13:42:54 EDT; 1h 56min ago
Docs: man:firewalld(1)
Main PID: 631 (firewalld)
CGroup: /system.slice/firewalld.service
└─631 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid
Oct 13 13:42:55 localhost.localdomain firewalld[631]: WARNING: ICMP type 'reject-route' is not supported by the kernel for ipv6.
Oct 13 13:42:55 localhost.localdomain firewalld[631]: WARNING: reject-route: INVALID_ICMPTYPE: No supported ICMP type., ignoring for run-time.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: ICMP type 'beyond-scope' is not supported by the kernel for ipv6.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: beyond-scope: INVALID_ICMPTYPE: No supported ICMP type., ignoring for run-time.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: ICMP type 'failed-policy' is not supported by the kernel for ipv6.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: failed-policy: INVALID_ICMPTYPE: No supported ICMP type., ignoring for run-time.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: ICMP type 'reject-route' is not supported by the kernel for ipv6.
Oct 13 15:19:41 localhost.localdomain firewalld[631]: WARNING: reject-route: INVALID_ICMPTYPE: No supported ICMP type., ignoring for run-time.
[donnie@localhost ~]$
firewalld 区域
firewalld 是一个相当独特的工具,因为它带有几个预配置的区域和服务。如果您查看您的 CentOS 机器的/usr/lib/firewalld/zones
目录,您将看到以.xml
格式的区域文件:
[donnie@localhost ~]$ cd /usr/lib/firewalld/zones
[donnie@localhost zones]$ ls
block.xml dmz.xml drop.xml external.xml home.xml internal.xml public.xml trusted.xml work.xml
[donnie@localhost zones]$
每个区域文件都指定了要打开的端口以及要为各种给定情况阻止的端口。区域还可以包含有关 ICMP 消息、转发端口、伪装信息和丰富语言规则的规则。
例如,公共区域的.xml
文件,它被设置为默认值,看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>Public</short>
<description>For use in public areas. You do not trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
<service name="ssh"/>
<service name="dhcpv6-client"/>
</zone>
在service name
行中,您可以看到唯一打开的端口是用于安全外壳访问和用于 DHCPv6 发现的端口。查看home.xml
文件,您将看到它还打开了用于多播 DNS 的端口,以及允许此计算机从 Samba 服务器或 Windows 服务器访问共享目录的端口:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>Home</short>
<description>For use in home areas. You mostly trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.</description>
<service name="ssh"/>
<service name="mdns"/>
<service name="samba-client"/>
<service name="dhcpv6-client"/>
</zone>
firewall-cmd
实用程序是您用于配置 firewalld 的工具。您可以使用它查看系统上区域文件的列表,而无需cd
到区域文件目录中:
[donnie@localhost ~]$ sudo firewall-cmd --get-zones
[sudo] password for donnie:
block dmz drop external home internal public trusted work
[donnie@localhost ~]$
查看每个区域配置的快速方法是使用--list-all-zones
选项:
[donnie@localhost ~]$ sudo firewall-cmd --list-all-zones
block
target: %%REJECT%%
icmp-block-inversion: no
interfaces:
sources:
services:
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
, , ,
, , ,
当然,这只是输出的一部分,因为所有区域的列表超出了我们可以在这里显示的范围。更有可能的是,您只想查看有关特定区域的信息:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=internal
internal
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh mdns samba-client dhcpv6-client
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
因此,internal
区域允许ssh
、mdns
、samba-client
和dhcpv6-client
服务。这对于在内部局域网上设置客户端机器非常方便。
任何给定的服务器或客户端都将安装一个或多个网络接口适配器。机器中的每个适配器可以分配一个且仅一个 firewalld 区域。要查看默认区域:
[donnie@localhost ~]$ sudo firewall-cmd --get-default-zone
public
[donnie@localhost ~]$
这很好,但它并没有告诉您与该区域关联的任何网络接口的信息。要查看该信息:
[donnie@localhost ~]$ sudo firewall-cmd --get-active-zones
public
interfaces: enp0s3
[donnie@localhost ~]$
当您首次安装 Red Hat 或 CentOS 时,防火墙将已经处于活动状态,并且公共区域将作为默认值。现在,假设您正在将服务器设置在 DMZ 中,并且希望确保其防火墙针对此进行了锁定。您可以将默认区域更改为dmz
区域。让我们看看dmz.xml
文件,看看它对我们有什么作用:
<?xml version="1.0" encoding="utf-8"?>
<zone>
<short>DMZ</short>
<description>For computers in your demilitarized zone that are publicly-accessible with limited access to your internal network. Only selected incoming connections are accepted.</description>
<service name="ssh"/>
</zone>
因此,DMZ 允许的唯一事物是安全外壳。好的,现在足够了,让我们将dmz
区域设置为默认值:
[donnie@localhost ~]$ sudo firewall-cmd --set-default-zone=dmz
[sudo] password for donnie:
success
[donnie@localhost ~]$
我们将验证:
[donnie@localhost ~]$ sudo firewall-cmd --get-default-zone
dmz
[donnie@localhost ~]$
我们一切都很好。除了在 DMZ 中面向互联网的服务器可能需要做的不仅仅是允许 SSH 连接。这就是我们将使用 firewalld 服务的地方。但是,在我们看看之前,让我们考虑另一个重要的问题。
不要修改/usr/lib/firewalld
目录中的文件。每当您修改 firewalld 配置时,您会看到修改后的文件出现在/etc/firewalld
目录中。到目前为止,我们只修改了默认区域。因此,我们将在/etc/firewalld
中看到这个:
[donnie@localhost ~]$ sudo ls -l /etc/firewalld
total 12
-rw-------. 1 root root 2003 Oct 11 17:37 firewalld.conf
-rw-r--r--. 1 root root 2006 Aug 4 17:14 firewalld.conf.old
. . .
我们可以对这两个文件进行diff
,以查看它们之间的差异:
[donnie@localhost ~]$ sudo diff /etc/firewalld/firewalld.conf /etc/firewalld/firewalld.conf.old
6c6
< DefaultZone=dmz
---
> DefaultZone=public
[donnie@localhost ~]$
因此,这两个文件中较新的文件显示dmz
区域现在是默认区域。
要获取有关 firewalld 区域的更多信息,请输入:
man firewalld.zones
firewalld 服务
每个服务文件都包含需要为特定服务打开的端口列表。可选地,服务文件可能包含一个或多个目标地址,或调用任何所需的模块,例如用于连接跟踪。对于某些服务,您只需要打开一个端口。其他服务,例如 Samba 服务,需要打开多个端口。无论哪种方式,有时记住与每个服务相关的服务名称比端口号更方便。
服务文件位于/usr/lib/firewalld/services
目录中。您可以使用firewall-cmd
命令查看它们的列表,就像您可以查看区域列表一样:
[donnie@localhost ~]$ sudo firewall-cmd --get-services
[sudo] password for donnie:
RH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client dns docker-registry dropbox-lansync elasticsearch freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp ganglia-client ganglia-master high-availability http https imap imaps ipp ipp-client ipsec iscsi-target kadmin kerberos kibana klogin kpasswd kshell ldap ldaps libvirt libvirt-tls managesieve mdns mosh mountd ms-wbt mssql mysql nfs nrpe ntp openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy proxy-dhcp ptp pulseaudio puppetmaster quassel radius rpc-bind rsh rsyncd samba samba-client sane sip sips smtp smtp-submission smtps snmp snmptrap spideroak-lansync squid ssh synergy syslog syslog-tls telnet tftp tftp-client tinc tor-socks transmission-client vdsm vnc-server wbem-https xmpp-bosh xmpp-client xmpp-local xmpp-server
[donnie@localhost ~]$
dropbox-lansync
服务对我们 Dropbox 用户非常有用。让我们看看这打开了哪些端口:
[donnie@localhost ~]$ sudo firewall-cmd --info-service=dropbox-lansync
[sudo] password for donnie:
dropbox-lansync
ports: 17500/udp 17500/tcp
protocols:
source-ports:
modules:
destination:
[donnie@localhost ~]$
看起来 Dropbox 使用端口17500
UDP 和 TCP。
现在,假设我们在 DMZ 中设置了我们的 Web 服务器,并将dmz
区域设置为其默认值:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=dmz
dmz (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
sources:
services: ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
正如我们之前看到的,只有安全外壳端口是打开的。让我们修复一下,以便用户实际访问我们的网站:
[donnie@localhost ~]$ sudo firewall-cmd --add-service=http
success
[donnie@localhost ~]$
当我们再次查看dmz
区域的信息时,我们会看到:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=dmz
dmz (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
sources:
services: ssh http
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
我们看到http
服务现在是允许的。但是当我们在info
命令中添加--permanent
选项时会发生什么:
[donnie@localhost ~]$ sudo firewall-cmd --permanent --info-zone=dmz
dmz
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
糟糕!http
服务不在这里。怎么回事?
对于任何命令行对区域或服务的更改,您都需要添加--permanent
选项,以使更改在重新启动后持久生效。但是,如果没有--permanent
选项,更改将立即生效。有了--permanent
选项,您必须重新加载防火墙配置才能使更改生效。为了演示,我将重新启动虚拟机以摆脱http
服务。
好的,我已经重新启动,http
服务现在已经消失了:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=dmz
[sudo] password for donnie:
dmz (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
sources:
services: ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
这次,我将使用一个命令添加两个服务,并指定更改为永久性:
[donnie@localhost ~]$ sudo firewall-cmd --permanent --add-service={http,https}
[sudo] password for donnie:
success
[donnie@localhost ~]$
您可以使用单个命令添加尽可能多的服务,但是您必须用逗号分隔它们,并在一对花括号中将整个列表括起来。让我们看看结果:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=dmz
dmz (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
sources:
services: ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
自从我们决定将此配置变为永久性后,它还没有生效。但是,如果我们在--info-zone
命令中添加--permanent
选项,我们会看到配置文件确实已经更改:
[donnie@localhost ~]$ sudo firewall-cmd --permanent --info-zone=dmz
dmz
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh http https
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[donnie@localhost ~]$
现在,我们需要通过重新加载配置来使更改生效:
[donnie@localhost ~]$ sudo firewall-cmd --reload
success
[donnie@localhost ~]$
再次运行sudo firewall-cmd --info-zone=dmz
命令,您将看到新配置现在已生效。
要从区域中删除服务,只需用--remove-service
替换--add-service
。
请注意,在所有这些服务命令中,我们从未指定我们正在处理的区域。这是因为如果我们不指定区域,firewalld 会假定我们正在处理默认区域。如果要将服务添加到除默认区域以外的其他区域,只需在命令中添加--zone=
选项。
向 firewalld 区域添加端口
拥有服务文件很方便,只是并非您需要运行的每个服务都有自己预定义的服务文件。假设您在服务器上安装了 Webmin,它需要打开端口10000/tcp
。快速的grep
操作将显示端口10000
不在我们预定义的任何服务中:
donnie@localhost services]$ pwd
/usr/lib/firewalld/services
[donnie@localhost services]$ grep '10000' *
[donnie@localhost services]$
因此,让我们将该端口添加到我们的默认区域,即dmz
区域:
donnie@localhost ~]$ sudo firewall-cmd --add-port=10000/tcp
[sudo] password for donnie:
success
[donnie@localhost ~]$
同样,这不是永久性的,因为我们没有包括--permanent
选项。让我们再做一次,然后重新加载:
[donnie@localhost ~]$ sudo firewall-cmd --permanent --add-port=10000/tcp
success
[donnie@localhost ~]$ sudo firewall-cmd --reload
success
[donnie@localhost ~]$
您还可以通过在一对花括号中包含逗号分隔的列表一次添加多个端口,就像我们在服务中所做的那样(是的,我故意没有加上--permanent
):
[donnie@localhost ~]$ sudo firewall-cmd --add-port={636/tcp,637/tcp,638/udp}
success
[donnie@localhost ~]$
当然,您也可以用--remove-port
替换--add-port
来从区域中删除端口。
firewalld 丰富的语言规则
到目前为止,我们所看到的可能是您在一般使用场景中所需的全部内容,但是,为了更精细的控制,您需要了解丰富的语言规则。(是的,这确实是它们的名称。)
与 iptables 规则相比,丰富的语言规则稍微不那么神秘,并且更接近普通英语。因此,如果您是新手编写防火墙规则,您可能会发现丰富的语言更容易学习。另一方面,如果您已经习惯编写 iptables 规则,您可能会发现丰富语言的某些元素有点古怪。让我们看一个例子:
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="200.192.0.0/24" service name="http" drop'
因此,我们正在添加一个丰富的规则。请注意,整个规则被一对单引号包围,并且每个参数的分配值被一对双引号包围。使用此规则,我们正在说我们正在使用 IPv4,并且我们希望静默地阻止http
端口接受来自200.192.0.0/24
网络的数据包。我们没有使用--permanent
选项,因此当我们重新启动机器时,此规则将消失。让我们看看我们的区域在添加了这条新规则后是什么样子:
[donnie@localhost ~]$ sudo firewall-cmd --info-zone=dmz
[sudo] password for donnie:
dmz (active)
target: default
icmp-block-inversion: no
interfaces: enp0s3
sources:
services: ssh http https
ports: 10000/tcp 636/tcp 637/tcp 638/udp
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
rule family="ipv4" source address="200.192.0.0/24" service name="http" drop
[donnie@localhost ~]$
丰富的规则显示在底部。在我们测试了这条规则以确保它能够满足我们的需求之后,我们将使其永久化:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="200.192.0.0/24" service name="http" drop'
sudo firewall-cmd --reload
您可以轻松地通过将family="ipv4"
替换为family="ipv6"
并提供适当的 IPv6 地址范围来为 IPv6 编写规则。
有些规则是通用的,适用于 IPv4 或 IPv6。假设我们想要记录关于网络时间协议(NTP)数据包的消息,并且您希望每分钟记录不超过一条消息。创建该规则的命令如下:
sudo firewall-cmd --permanent --add-rich-rule='rule service name="ntp" audit limit value="1/m" accept'
当然,firewalld 丰富的语言规则还有很多内容,我们无法在这里全部呈现。但是,至少您现在知道了基础知识。有关更多信息,请参阅man
页面:
man firewalld.richlanguage
firewalld 命令的实践实验
通过这个实验,您将练习基本的 firewalld 命令:
- 登录到您的 CentOS 7 虚拟机并运行以下命令。观察每个命令后的输出:
sudo firewall-cmd --get-zones
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
- 简要查看处理 firewalld 区域的
man
页面:
man firewalld.zones
man firewalld.zone
(是的,有两个。一个解释了区域配置文件,另一个解释了区域本身。)
- 查看所有可用区域的配置信息:
sudo firewall-cmd --list-all-zones
- 查看预定义服务列表。然后,查看有关
dropbox-lansync
服务的信息:
sudo firewall-cmd --get-services
sudo firewall-cmd --info-service=dropbox-lansync
- 将默认区域设置为
dmz
。查看有关该区域的信息,添加http
和https
服务,然后再次查看区域信息:
sudo firewall-cmd --set-default-zone=dmz
sudo firewall-cmd --permanent --add-service={http,https}
sudo firewall-cmd --info-zone=dmz
sudo firewall-cmd --permanent --info-zone=dmz
- 重新加载防火墙配置,并再次查看区域信息。还要查看正在允许的服务列表:
sudo firewall-cmd --reload
sudo firewall-cmd --info-zone=dmz
sudo firewall-cmd --list-services
- 永久打开端口
10000/tcp
,并查看结果:
sudo firewall-cmd --permanent --add-port=10000/tcp
sudo firewall-cmd --list-ports
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports
sudo firewall-cmd --info-zone=dmz
- 删除刚刚添加的端口:
sudo firewall-cmd --permanent --remove-port=10000/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-ports
sudo firewall-cmd --info-zone=dmz
- 查看 firewalld 的主要页面列表:
apropos firewall
- 实验结束。
nftables-一种更通用的防火墙系统
现在让我们把注意力转向 nftables,这个新来的。那么,nftables 有什么优点?(是的,这是一个双关语。)
-
现在,您可以忘记需要单独的守护程序和实用程序来处理所有不同的网络组件。 iptables,ip6tables,ebtables 和 arptables 的功能现在都合并在一个整洁的软件包中。 nft 实用程序现在是您唯一需要的防火墙实用程序。
-
使用 nftables,您可以创建多维树来显示您的规则集。这使得故障排除变得更加容易,因为现在更容易跟踪数据包通过所有规则。
-
使用 iptables,默认情况下会安装过滤器、NAT、mangle 和安全表,无论您是否使用每个表。使用 nftables,您只创建您打算使用的表,从而提高性能。
-
与 iptables 不同,您可以在一条规则中指定多个操作,而不必为每个操作创建多个规则。
-
与 iptables 不同,新规则是原子性添加的。(这是说,不再需要重新加载整个规则集才能添加一个规则。)
-
nftables 具有自己的内置脚本引擎,允许您编写更高效和更易读的脚本。
-
如果您已经有很多仍然需要使用的 iptables 脚本,您可以安装一组实用程序,以帮助您将它们转换为 nftables 格式。
nftables 表和链
如果您习惯于 iptables,您可能会认识到一些 nftables 术语。唯一的问题是,一些术语以不同的方式使用,具有不同的含义。这就是我所说的一些内容:
-
Tables: nftables 中的表指的是特定的协议家族。表类型有 ip、ip6、inet、arp、bridge 和 netdev。
-
Chains: nftables 中的链大致相当于 iptables 中的表。例如,在 nftables 中,你可以有 filter、route 或 NAT 链。
开始使用 nftables
让我们从 Ubuntu 虚拟机的干净快照开始,并安装 nftables 包。
nftables 的命令行实用程序是nft
。你可以在 Bash shell 中执行nft
命令,或者可以执行sudo nft -i
以运行交互模式下的 nft。对于我们目前的演示,我们将在 Bash shell 中运行命令。
现在,让我们来看一下已安装的表的列表:
sudo apt install nftables
sudo nft list tables
嗯...你没有看到任何表,对吧?所以,让我们加载一些表。
如果你在/etc
目录中查看nftables.conf
文件,你会看到一个基本的 nft 防火墙配置的开端:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
# accept any localhost traffic
iif lo accept
# accept traffic originated from us
ct state established,related accept
# activate the following line to accept
common local services
# tcp dport { 22, 80, 443 } ct state new accept
# accept neighbour discovery otherwise
IPv6 connectivity breaks.
ip6 nexthdr icmpv6 icmpv6 type { nd-neighbor-solicit,
nd-router-advert, nd-neighbor-advert } accept
# count and drop any other traffic
counter drop
}
}
这是所有这些意思的分解:
-
#!/usr/sbin/nft -f
: 虽然你可以用 nftables 命令创建普通的 Bash shell 脚本,但最好使用 nftables 附带的内置脚本引擎。这样,我们可以使我们的脚本更易读,并且不必在每个想要执行的命令前面输入nft
。 -
flush ruleset
: 我们想要从一个干净的状态开始,所以我们将清除已经加载的任何规则。 -
table inet filter
: 这创建了一个 inet 家族的过滤器,适用于 IPv4 和 IPv6。这个表的名称是filter
,但也可以是更具描述性的名称。 -
chain input
: 在第一对花括号中,我们有一个名为input
的链。(再次强调,名称可以更具描述性。) -
type filter hook input priority 0;
: 在接下来的一对花括号中,我们定义了我们的链,然后列出了规则。这个链被定义为filter
类型。hook input
表示这个链是用来处理传入的数据包的。因为这个链既有hook
又有priority
,所以它将直接接受来自网络堆栈的数据包。 -
最后,我们有一个非常基本的主机防火墙的标准规则,从
iif
规则开始,允许环回接口接受数据包(iif代表输入接口)。 -
接下来是标准的连接跟踪(
ct
)规则,它接受对这个主机发出的连接请求的流量。 -
然后,有一个被注释掉的规则,用于接受安全外壳和安全和非安全的网页流量。
ct state new
表示防火墙将允许其他主机在这些端口上启动与我们服务器的连接。 -
ipv6
规则接受邻居发现数据包,允许 IPv6 功能。 -
最后的
counter drop
规则会默默地阻止所有其他流量,并计算它阻止的数据包和字节数。这是一个例子,说明一个规则可以执行两种不同的操作。
如果你的 Ubuntu 服务器上只需要一个基本的、简单的防火墙,最好的办法就是编辑/etc/nftables.conf
文件以满足你自己的需求。首先,让我们从tcp dport
行的前面删除注释符号,并且去掉80
和443
端口。现在这行应该是这样的:
tcp dport 22 ct state new accept
请注意,当你只打开一个端口时,你不需要将该端口号括在花括号中。当打开多个端口时,只需在花括号中包含逗号分隔的列表,第一个元素前面和最后一个元素后面留有空格。
加载配置文件,并查看结果:
sudo nft -f /etc/nftables.conf
donnie@ubuntu2:~$ sudo nft list table inet filter
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
iif lo accept
ct state established,related accept
tcp dport ssh ct state new accept
ip6 nexthdr ipv6-icmp icmpv6 type { nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert} accept
counter packets 67 bytes 10490 drop
}
}
donnie@ubuntu2:~$
现在,假设我们想要阻止某些 IP 地址到达这台机器的安全外壳端口。我们可以编辑文件,在打开22
端口的规则之上放置一个drop
规则。文件的相关部分将如下所示:
tcp dport 22 ip saddr { 192.168.0.7, 192.168.0.10 } drop
tcp dport 22 ct state new accept
重新加载文件后,我们将阻止来自两个不同 IPv4 地址的 SSH 访问。请注意,我们将drop
规则放在accept
规则之前,因为如果首先读取accept
规则,drop
规则将永远不会生效。
另一个非常酷的事情要注意的是,我们在同一个配置文件中混合了 IPv4(ip)规则和 IPv6(ip6)规则。这就是使用 inet 类型表的美妙之处。为了简单和灵活性,您应尽可能使用 inet 表,而不是单独的 ip 和 ip6 表。
大多数情况下,当您只需要一个简单的主机防火墙时,最好的选择就是使用此nftables.conf
文件作为起点,并编辑文件以满足自己的需求。但是,有时您可能会发现命令行组件也很有用。
使用 nft 命令
使用 nft 实用程序有两种方法。您可以直接从 Bash shell 执行所有操作,每个要执行的操作之前都要加上 nft,然后是nft
子命令。您还可以在交互模式下使用 nft。对于我们现在的目的,我们将使用 Bash shell。
让我们首先删除先前的配置,并创建一个 inet 表,因为我们希望它适用于 IPv4 和 IPv6。我们希望给它一个相当描述性的名称,所以让我们称之为ubuntu_filter
:
sudo nft delete table inet filter
sudo nft list tables
sudo nft add table inet ubuntu_filter
sudo nft list tables
接下来,我们将在我们刚刚创建的表中添加一个input
过滤器链。(请注意,由于我们是从 Bash shell 执行此操作,因此需要使用反斜杠转义分号。)
sudo nft add chain inet ubuntu_filter input { type filter hook input priority 0\; policy drop\; }
在此命令中,ubuntu_filter
之后的第一个input
是链的名称。(我们本可以给它一个更具描述性的名称,但目前,input
就可以了。)在一对花括号内,我们正在为此链设置参数。
每个 nftables 协议族都有自己的一组钩子,定义了数据包的处理方式。目前,我们只关注 ip/ip6/inet 族,它们具有以下钩子:
-
预处理
-
输入
-
前进
-
产出
-
出口
其中,我们目前只关注输入和输出钩子,这将适用于过滤器类型链。通过为我们的输入链指定一个钩子和优先级,我们正在表示我们希望此链成为基本链,它将直接从网络堆栈接受数据包。您还会看到,某些参数必须以分号结尾,如果您从 Bash shell 运行命令,则需要用反斜杠转义分号。最后,我们正在指定默认策略为drop
。如果我们没有指定drop
作为默认策略,那么默认策略将是accept
。
您输入的每个nft
命令都会立即生效。因此,如果您远程执行此操作,一旦创建了具有默认drop
策略的过滤器链,您将立即断开安全外壳连接。
有些人喜欢创建具有默认accept
策略的链,然后在最后添加一个drop
规则。其他人喜欢创建具有默认drop
策略的链,然后在最后不添加 drop 规则。使用默认accept
规则的优势在于,您可以远程执行这些防火墙命令,而不必担心被锁定。
验证链是否已添加,您应该会看到类似于此的内容:
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter
[sudo] password for donnie:
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
}
}
donnie@ubuntu2:~$
这很好,但我们仍然需要一些规则。让我们从连接跟踪规则和打开安全外壳端口的规则开始。然后我们将验证它们是否已添加:
sudo nft add rule inet ubuntu_filter input ct state established accept
sudo nft add rule inet ubuntu_filter input tcp dport 22 ct state new accept
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established accept
tcp dport ssh ct state new accept
}
}
donnie@ubuntu2:~
好的,看起来不错。您现在有一个基本的工作防火墙,允许安全外壳连接。好吧,除了我们在 ufw 章节中所做的一样,我们忘记创建一个允许环回适配器接受数据包的规则。由于我们希望此规则位于规则列表的顶部,因此我们将使用insert
而不是add
:
sudo nft insert rule inet ubuntu_filter input iif lo accept
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established accept
tcp dport ssh ct state new accept
}
}
donnie@ubuntu2:~$
现在,我们已经准备就绪。但是,如果我们想在特定位置插入规则怎么办?为此,您需要使用带有-a
选项的list
来查看handles
规则:
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter -a
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept # handle 4
ct state established accept # handle 2
tcp dport ssh ct state new accept # handle 3
}
}
donnie@ubuntu2:~$
正如您所看到的,句柄的编号没有真正的规律或原因。假设我们想要插入一个关于阻止某些 IP 地址访问安全外壳端口的规则。我们看到ssh accept
规则是handle 3
,所以我们需要在它之前插入我们的drop
规则。我们的命令看起来像这样:
sudo nft insert rule inet ubuntu_filter input position 3 tcp dport 22 ip saddr { 192.168.0.7, 192.168.0.10 } drop
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter -a
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept # handle 4
ct state established accept # handle 2
tcp dport ssh ip saddr { 192.168.0.10, 192.168.0.7} drop # handle 6
tcp dport ssh ct state new accept # handle 3
}
}
donnie@ubuntu2:~$
因此,要将规则放置在具有handle 3
标签的规则之前,我们必须插入
到位置 3
。我们刚刚插入的新规则具有标签handle 6
。要删除规则,我们将指定规则的句柄号码:
sudo nft delete rule inet ubuntu_filter input handle 6
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter -a
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept # handle 4
ct state established accept # handle 2
tcp dport ssh ct state new accept # handle 3
}
}
donnie@ubuntu2:~$
与 iptables 一样,您从命令行执行的所有操作在重新启动机器后都会消失。为了使其永久生效,让我们将list
子命令的输出重定向到一个配置文件中(当然,我们需要给文件一个与默认文件名不同的唯一名称):
sudo sh -c "nft list table inet ubuntu_filter > new_nftables.conf"
由于 Bash shell 的一个怪癖,我们无法像通常那样将输出重定向到/etc
目录中的文件,即使我们使用sudo
也不行。这就是为什么我不得不添加sh -c
命令,用双引号括起来的nft list
命令。现在,当我们查看文件时,我们会发现有一些东西丢失了:
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established accept
tcp dport ssh ct state new accept
}
}
你们这些敏锐的人会发现我们缺少flush
规则和shebang
行来指定我们想要解释此脚本的 shell。让我们添加它们:
#!/usr/sbin/nft -f
flush ruleset
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established accept
tcp dport ssh ct state new accept
}
}
好多了。让我们通过加载新配置并观察list
输出来测试它:
sudo nft -f /etc/new_nftables.conf
donnie@ubuntu2:~$ sudo nft list table inet ubuntu_filter
table inet ubuntu_filter {
chain input {
type filter hook input priority 0; policy drop;
iif lo accept
ct state established accept
tcp dport ssh ct state new accept
}
}
donnie@ubuntu2:~$
这就是创建自己的简单主机防火墙的全部内容。当然,与仅在文本编辑器中创建脚本文件不同,从命令行运行命令确实需要更多的输入。但是,这样做可以让您在创建规则时即时测试它们。以这种方式创建您的配置,然后将list
输出重定向到新的配置文件中,可以让您摆脱不得不跟踪所有这些花括号的负担。
还可以将我们刚刚执行的所有nft
命令放入一个常规的、老式的 Bash shell 脚本中。相信我,你真的不想这样做。只需像我们在这里所做的那样使用 nft-native 脚本格式,您将拥有一个性能更好、更易读的脚本。
Ubuntu 上的 nftables 实验
对于这个实验,您需要一个干净的 Ubuntu 虚拟机快照:
- 将您的 Ubuntu 虚拟机恢复到一个干净的快照,以清除您之前创建的任何防火墙配置。使用以下命令进行验证:
sudo ufw status
sudo iptables -L
您应该看到 iptables 列出的规则为空,ufw 状态应为inactive
。
- 安装
nftables
软件包:
sudo apt install nftables
- 列出表,不应该有任何输出。加载默认配置文件,并列出表和规则:
sudo nft list tables
sudo nft -f /etc/nftables.conf
sudo nft list tables
sudo nft list table inet filter
- 备份 nftables 配置文件:
sudo cp /etc/nftables.conf /etc/nftables.conf.bak
- 打开您的文本编辑器中的原始
/etc/nftables.conf
文件。在tcp dport . . . accept
行之前,插入以下行:
tcp dport ssh ip saddr { 192.168.0.7, 192.168.0.10 } drop
保存文件并退出文本编辑器。
- 重新加载配置并查看结果:
sudo nft list tables
sudo nft -f /etc/nftables.conf
sudo nft list tables
sudo nft list table inet filter
- 实验结束。
总结
在本章中,我们看了四种不同的 netfilter 防火墙前端。我们首先看了我们值得信赖的老朋友 iptables。我们看到,即使它已经存在很长时间并且仍然有效,它确实有一些缺点。然后我们看到 Ubuntu 的简化防火墙如何大大简化了设置基于 iptables 的防火墙。对于红帽用户,我们看了看 firewalld,这是特定于红帽类型的发行版。最后,我们通过查看最新的 Linux 防火墙技术 nftables 来结束了一切。
在分配的空间中,我只能呈现您设置基本主机保护所需的基本要点。但至少足够让您开始。
第四章:加密和 SSH 加固
您可能在一个超级秘密的政府机构工作,也可能只是一个普通的公民。 无论如何,您仍然有需要保护免受窥视的敏感数据。 商业机密、政府机密、个人机密——都需要保护。 像我们在第二章中看到的那样,通过限制权限设置来锁定用户的主目录只是问题的一部分; 我们还需要加密。
我们将在本章中查看的两种数据加密的一般类型旨在保护静止数据和传输数据。 我们将首先使用文件、分区和目录加密来保护静止数据。 然后,我们将介绍安全外壳(SSH)以保护传输数据。
在本章中,我们将涵盖:
-
GNU 隐私保护(GPG)
-
使用Linux 统一密钥设置(LUKS)加密分区
-
使用 eCryptfs 加密目录
-
使用 VeraCrypt 跨平台共享加密容器
-
确保 SSH 协议 1 已禁用
-
创建和管理无密码登录的密钥
-
禁用 root 用户登录
-
禁用用户名/密码登录
-
为 SFTP 用户设置 chroot 环境
GNU 隐私保护
我们将从GNU 隐私保护(GPG)开始。 这是 Phil Zimmermann 于 1991 年创建的Pretty Good Privacy的免费开源实现。 您可以使用其中任何一个来加密或加密签名文件或消息。 在本节中,我们将严格关注 GPG。
使用 GPG 有一些优势:
-
它使用强大、难以破解的加密算法。
-
它使用私钥/公钥方案,消除了以安全方式将密码传输给消息或文件接收者的需要。 相反,只需发送您的公钥,对于除预期接收者之外的任何人都是无用的。
-
您可以使用 GPG 仅加密自己的文件以供自己使用,就像您使用任何其他加密实用程序一样。
-
它可用于加密电子邮件消息,允许您对敏感电子邮件进行真正的端到端加密。
-
有一些图形用户界面类型的前端可用,使其使用起来更加容易。
但是,您可能知道,也有一些缺点:
-
与密码相比,使用公钥在您直接与您隐含信任的人一起工作时非常好。 但是,对于任何超出此范围的事情,例如向一般人群分发公钥以便每个人都可以验证您签名的消息,您将依赖于一个非常难以建立的信任网络模型。
-
对于电子邮件的端到端加密,您的电子邮件接收者也必须在其系统上设置 GPG,并知道如何使用它。 这可能在企业环境中起作用,但是希望您的朋友设置这个的时候好运。(我从来没有成功过让其他人设置电子邮件加密。)
-
如果您使用独立的电子邮件客户端,例如 Mozilla Thunderbird,您可以安装一个插件,该插件将自动加密和解密消息。 但是,每次发布新的 Thunderbird 更新时,插件都会中断,而且总是需要一段时间才能发布新的可用版本。
即使 GPG 有许多弱点,它仍然是共享加密文件和电子邮件的最佳方式之一。 GPG 预装在 Ubuntu Server 和 CentOS 上。 因此,您可以使用任一虚拟机进行这些演示。
创建您的 GPG 密钥
开始使用 GPG 需要您首先生成您的 GPG 密钥。 您将使用以下命令完成:
gpg --gen-key
请注意,由于您为自己设置这个,您不需要 sudo 特权。
此命令的输出太长,无法一次显示所有内容,因此我将显示其中相关部分,并解释其含义。
此命令的第一件事是在您的主目录中创建一个填充的.gnupg
目录:
gpg: directory `/home/donnie/.gnupg' created
gpg: new configuration file `/home/donnie/.gnupg/gpg.conf' created
gpg: WARNING: options in `/home/donnie/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/home/donnie/.gnupg/secring.gpg' created
gpg: keyring `/home/donnie/.gnupg/pubring.gpg' created
然后你将被要求选择你想要的密钥类型。我们将选择默认的 RSA 和 RSA。(RSA 密钥比较强大,比旧版 DSA 密钥更难破解。Elgamal 密钥也不错,但可能不受 GPG 旧版本支持。)
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection?
为了获得良好的加密,你需要选择至少 2048 位的密钥,因为任何更小的密钥现在都被认为是容易受到攻击的。由于 2048 恰好是默认值,我们将选择它:
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)
接下来,选择密钥在自动到期之前保持有效的时间。对于我们的目的,我们将选择默认的密钥不会过期
。
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
提供你的个人信息:
GnuPG needs to construct a user ID to identify your key.
Real name: Donald A. Tevault
Email address: donniet@something.net
Comment: No comment
You selected this USER-ID:
"Donald A. Tevault (No comment) <donniet@something.net>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit?
为你的私钥创建一个密码:
You need a Passphrase to protect your secret key.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
这可能需要一段时间,即使你正在做所有推荐的事情来创建熵。耐心等待,它最终会完成。通过在另一个窗口运行sudo yum upgrade
,我创建了足够的熵,以便进程不会花费太长时间:
gpg: /home/donnie/.gnupg/trustdb.gpg: trustdb created
gpg: key 19CAEC5B marked as ultimately trusted
public and secret key created and signed.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
pub 2048R/19CAEC5B 2017-10-26
Key fingerprint = 8DE5 8894 2E37 08C4 5B26 9164 C77C 6944 19CA EC5B
uid Donald A. Tevault (No comment) <donniet@something.net>
sub 2048R/37582F29 2017-10-26
验证密钥是否已创建:
[donnie@localhost ~]$ gpg --list-keys
/home/donnie/.gnupg/pubring.gpg
-------------------------------
pub 2048R/19CAEC5B 2017-10-26
uid Donald A. Tevault (No comment) <donniet@something.net>
sub 2048R/37582F29 2017-10-26
[donnie@localhost ~]$
还有,趁机看看你创建的文件:
[donnie@localhost ~]$ ls -l .gnupg
total 28
-rw-------. 1 donnie donnie 7680 Oct 26 13:22 gpg.conf
drwx------. 2 donnie donnie 6 Oct 26 13:40 private-keys-v1.d
-rw-------. 1 donnie donnie 1208 Oct 26 13:45 pubring.gpg
-rw-------. 1 donnie donnie 1208 Oct 26 13:45 pubring.gpg~
-rw-------. 1 donnie donnie 600 Oct 26 13:45 random_seed
-rw-------. 1 donnie donnie 2586 Oct 26 13:45 secring.gpg
srwxrwxr-x. 1 donnie donnie 0 Oct 26 13:40 S.gpg-agent
-rw-------. 1 donnie donnie 1280 Oct 26 13:45 trustdb.gpg
[donnie@localhost ~]$
这些文件是你的公钥和私钥环,你自己的gpg.conf
文件,一个随机种子文件和一个受信任的用户数据库。
对自己的文件进行对称加密
你可能会发现 GPG 对加密你自己的文件很有用,即使你从不打算与其他人分享。为此,你将使用对称加密,这涉及使用你自己的私钥进行加密。在尝试之前,你需要生成你的密钥,就像我在前一节中概述的那样。
对称密钥加密就是这样,对称的。这意味着用于加密文件的密钥与用于解密文件的密钥相同。如果你只是为了自己使用而加密文件,那就很好。但是,如果你需要与其他人共享加密文件,你需要想出一个安全的方法来给那个人密码。我的意思是,你肯定不想只是在明文电子邮件中发送密码。
让我们加密一个绝对不能落入错误手中的超级秘密文件:
[donnie@localhost ~]$ gpg -c secret_squirrel_stuff.txt
[donnie@localhost ~]$
请注意,-c
选项表示我选择使用对称加密为文件设置密码。你输入的密码将用于文件,而不是你的私钥。
这种方法的一个小缺陷是,GPG 会生成文件的加密副本,但也会保留原始的未加密文件:
[donnie@localhost ~]$ ls -l
total 1748
-rw-rw-r--. 1 donnie donnie 37 Oct 26 14:22 secret_squirrel_stuff.txt
-rw-rw-r--. 1 donnie donnie 94 Oct 26 14:22 secret_squirrel_stuff.txt.gpg
[donnie@localhost ~]$
让我们用shred
去掉那个未加密的文件。我们将使用-u
选项删除文件,使用-z
选项用零覆盖已删除的文件:
[donnie@localhost ~]$ shred -u -z secret_squirrel_stuff.txt
[donnie@localhost ~]$
看起来好像什么都没发生,因为shred
不会给出任何输出。但是,ls -l
会证明文件已经消失了。现在,如果我用less secret_squirrel_stuff.txt.gpg
查看加密文件,我将能够看到它的内容,之后会被要求输入我的私钥密码:
Shhh!!!! This file is super-secret.
secret_squirrel_stuff.txt.gpg (END)
只要我的私钥仍然加载到我的密钥环中,我就能够再次查看我的加密文件,而无需重新输入密码。现在,为了向你证明文件确实是加密的,我将创建一个共享目录,并将文件移动到那里供其他人访问:
sudo mkdir /shared
sudo chown donnie: /shared
sudo chmod 755 /shared
mv secret_squirrel_stuff.txt.gpg /shared
当我进入那个目录用less
查看文件时,我仍然可以看到它的内容,而无需重新输入密码。但现在,让我们看看当 Maggie 尝试查看文件时会发生什么:
[maggie@localhost shared]$ less secret_squirrel_stuff.txt.gpg
"secret_squirrel_stuff.txt.gpg" may be a binary file. See it anyway?
当她按下Y键查看时:
<8C>^M^D^C^C^B<BD>2=<D3>͈u<93><CE><C9>MОOy<B6>^O<A2><AD>}Rg9<94><EB><C4>^W^E<A6><8D><B9><B8><D3>(<98><C4>æF^_8Q2b<B8>C<B5><DB>^]<F1><CD>#<90>H<EB><90><C5>^S%X [<E9><EF><C7>
^@y+<FC><F2><BA><U+058C>H'+<D4>v<84>Y<98>G<D7>֊
secret_squirrel_stuff.txt.gpg (END)
可怜的 Maggie 真的很想看到我的文件,但她只能看到加密的胡言乱语。
我刚刚演示的是 GPG 的另一个优点。输入私钥密码一次后,你就可以查看任何加密文件,而无需手动解密它们,也无需重新输入密码。对于其他对称文件加密工具,比如 Bcrypt,你需要先手动解密文件才能查看它们。
但是,现在假设您不再需要加密此文件,并且希望解密它以便让其他人查看。只需使用gpg
和-d
选项:
[donnie@localhost shared]$ gpg -d secret_squirrel_stuff.txt.gpg
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
Shhh!!!! This file is super-secret.
gpg: WARNING: message was not integrity protected
[donnie@localhost shared]$
关于消息未经完整保护的警告
消息意味着我已加密该文件,但我从未签署该文件。没有数字签名,其他人可以更改文件而我不知道,我将无法证明我是文件的发起者。(不要担心,我们马上就会讨论文件签名。)
实践实验-结合 gpg 和 tar 进行加密备份
在这个实验中,您将结合tar
和gpg
在模拟备份设备上创建加密备份。您可以在您的任一虚拟机上执行此实验:
- 首先,通过以下命令创建您的 GPG 密钥。
gpg --gen-key
- 在您的主目录中创建一些虚拟文件,这样您就有了一些备份内容:
touch {file1.txt,file2.txt,file3.txt,file4.txt}
- 在文件系统的根目录创建一个备份目录。(在现实生活中,您可能会将备份目录放在一个单独的设备上,但现在,这样做也可以。)更改目录的所有权为您自己的帐户,并设置权限,以便只有您可以访问它:
sudo mkdir /backup
sudo chown your_username: /backup
sudo chmod 700 /backup
- 创建您自己主目录的加密备份文件。压缩是可选的,但我们将继续使用
xz
以获得最佳压缩效果。(请注意,您需要使用sudo
,因为您主目录中的.viminfo
目录归根用户所有。):
cd /home
sudo tar cJvf - your_username/ | gpg -c >
/backup/your_username_backup.tar.xz.gpg
- 现在,假设您的主目录被删除,或者您意外删除了自己主目录中的一些重要文件。在
/backup
目录中提取并解密原始主目录:
cd /backup
sudo gpg -d your_username.tar.xz.gpg | tar xvJ
ls -la your_username/
请注意,通过将tar
与gpg
结合使用,tar
的-C
选项自动将您的主目录放回/home
目录的操作将无法进行。因此,您需要手动将提取的目录复制回/home
,或者在提取之前将加密备份文件移动到/home
。此外,请注意,使用gpg
提取加密存档时,文件的所有权将更改为提取存档的人的所有权。因此,这可能不是备份整个具有多个用户主目录的/home
目录的一个好选择。最后,由于这将创建一个巨大的存档文件,存档文件中的任何类型的损坏都可能导致您丢失整个备份。
- 实验结束。
使用非对称加密和签名的私钥和公钥
对称加密对于仅在本地使用 GPG 处理自己的东西非常有用,但是如果您想与他人分享加密文件,并确保他们可以解密该文件怎么办?使用对称加密,您需要找到一种安全的方式将文件的密码传输给文件的接收者。这样做将始终存在第三方可能拦截密码的风险,然后可以进入您的文件。这就是非对称加密发挥作用的地方。为了演示,我将创建一个文件,对其进行加密,并将其发送给我的朋友 Frank 进行解密。
非对称加密是非对称的。非对称意味着您将使用一个密钥加密文件,使用另一个密钥解密文件。您将保留私钥,并将其视为生命,但您将与全世界分享公钥。这样做的美妙之处在于,您可以与另一个人分享加密文件,只有该人才能解密。这一切都可以在不必与接收者分享密码的情况下完成。
首先,我和 Frank 都必须创建一个密钥集,就像我们已经向您展示的那样。接下来,我们每个人都需要提取我们的公钥,并将它们发送给彼此。我们将把密钥提取到一个 ASCII 文本文件中:
cd .gnupg
gpg --export -a -o donnie_public-key.txt
donnie@ubuntu:~/.gnupg$ ls -l
total 36
-rw-rw-r-- 1 donnie donnie 1706 Oct 27 18:14 donnie_public-key.txt
. . .
frank@ubuntu:~/.gnupg$ ls -l
total 36
-rw-rw-r-- 1 frank frank 1714 Oct 27 18:18 frank_public-key.txt
通常情况下,参与者要么通过电子邮件附件发送彼此的密钥,要么将密钥放在共享目录中。在这种情况下,弗兰克和我将收到彼此的公钥文件,并将它们放入我们各自的.gnupg
目录中。一旦完成,我们就准备好导入彼此的密钥了:
donnie@ubuntu:~/.gnupg$ gpg --import frank_public-key.txt
gpg: key 4CFC6990: public key "Frank Siamese (I am a cat.) <frank@any.net>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
donnie@ubuntu:~/.gnupg$
frank@ubuntu:~/.gnupg$ gpg --import donnie_public-key.txt
gpg: key 9FD7014B: public key "Donald A. Tevault <donniet@something.net>" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)
frank@ubuntu:~/.gnupg$
现在是好东西的时候了。我为弗兰克创建了一个超级秘密的消息,并且会用非对称加密(-e
)和签名(-s
)来加密它。(签署消息是验证消息确实是我发出的,而不是冒名顶替者发出的。)
donnie@ubuntu:~$ gpg -s -e secret_stuff_for_frank.txt
You need a passphrase to unlock the secret key for
user: "Donald A. Tevault <donniet@something.net>"
2048-bit RSA key, ID 9FD7014B, created 2017-10-27
gpg: gpg-agent is not available in this session
You did not specify a user ID. (you may use "-r")
Current recipients:
Enter the user ID. End with an empty line: frank
gpg: CD8104F7: There is no assurance this key belongs to the named user
pub 2048R/CD8104F7 2017-10-27 Frank Siamese (I am a cat.) <frank@any.net>
Primary key fingerprint: 4806 7483 5442 D62B B9BD 95C1 9564 92D4 4CFC 6990
Subkey fingerprint: 9DAB 7C3C 871D 6711 4632 A5E0 6DDD E3E5 CD81 04F7
It is NOT certain that the key belongs to the person named
in the user ID. If you *really* know what you are doing,
you may answer the next question with yes.
Use this key anyway? (y/N) y
Current recipients:
2048R/CD8104F7 2017-10-27 "Frank Siamese (I am a cat.) <frank@any.net>"
Enter the user ID. End with an empty line:
donnie@ubuntu:~$
所以,我必须做的第一件事是输入我的私钥密码。在要求输入用户 ID 的地方,我输入了frank
,因为他是我消息的预期接收者。但是,看看之后的那一行,那里写着没有保证这个密钥属于指定的用户
。那是因为我还没有信任弗兰克的公钥。我们稍后会解决这个问题。输出的最后一行再次要求输入用户 ID,这样我们就可以指定多个接收者。但是,弗兰克现在是我唯一关心的人,所以我只是按下Enter键来跳出例行程序。这导致了我给弗兰克的消息的.gpg
版本:
donnie@ubuntu:~$ ls -l
total 8
. . .
-rw-rw-r-- 1 donnie donnie 143 Oct 27 18:37 secret_stuff_for_frank.txt
-rw-rw-r-- 1 donnie donnie 790 Oct 27 18:39 secret_stuff_for_frank.txt.gpg
donnie@ubuntu:~$
我的最后一步是通过任何可用的方式发送 Frank 的加密消息文件。
当弗兰克收到他的消息时,他将使用-d
选项来查看它:
frank@ubuntu:~$ gpg -d secret_stuff_for_frank.txt.gpg
You need a passphrase to unlock the secret key for
user: "Frank Siamese (I am a cat.) <frank@any.net>"
2048-bit RSA key, ID CD8104F7, created 2017-10-27 (main key ID 4CFC6990)
gpg: gpg-agent is not available in this session
gpg: encrypted with 2048-bit RSA key, ID CD8104F7, created 2017-10-27
"Frank Siamese (I am a cat.) <frank@any.net>"
This is TOP SECRET stuff that only Frank can see!!!!!
If anyone else see it, it's the end of the world as we know it.
(With apologies to REM.)
gpg: Signature made Fri 27 Oct 2017 06:39:15 PM EDT using RSA key ID 9FD7014B
gpg: Good signature from "Donald A. Tevault <donniet@something.net>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB0B 31B8 876D 9B2C 7F12 9FC3 886F 3357 9FD7 014B
frank@ubuntu:~$
弗兰克输入他的私钥密码,然后他看到了消息。在底部,他看到了关于我的公钥不受信任的警告,以及没有迹象表明签名属于所有者
。好吧,既然弗兰克认识我,他确切地知道这个公钥确实是我的,他可以将我的公钥添加到受信任列表中:
frank@ubuntu:~$ cd .gnupg
frank@ubuntu:~/.gnupg$ gpg --edit-key donnie
gpg (GnuPG) 1.4.20; Copyright (C) 2015 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u
pub 2048R/9FD7014B created: 2017-10-27 expires: never usage: SC
trust: ultimate validity: ultimate
sub 2048R/9625E7E9 created: 2017-10-27 expires: never usage: E
[ultimate] (1). Donald A. Tevault <donniet@something.net>
gpg>
这个输出的最后一行是gpg
shell 的命令提示符。弗兰克关心信任,所以他会输入trust
命令:
gpg> trust
pub 2048R/9FD7014B created: 2017-10-27 expires: never usage: SC
trust: unknown validity: unknown
sub 2048R/9625E7E9 created: 2017-10-27 expires: never usage: E
[ unknown] (1). Donald A. Tevault <donniet@something.net>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y
弗兰克认识我已经很长时间了,他确切地知道是我发送了这个密钥。所以,他选择了5
号选项来获得终极信任。一旦弗兰克退出并重新登录,这种信任就会生效:
frank@ubuntu:~$ gpg -d secret_stuff_for_frank.txt.gpg
You need a passphrase to unlock the secret key for
user: "Frank Siamese (I am a cat.) <frank@any.net>"
2048-bit RSA key, ID CD8104F7, created 2017-10-27 (main key ID 4CFC6990)
gpg: gpg-agent is not available in this session
gpg: encrypted with 2048-bit RSA key, ID CD8104F7, created 2017-10-27
"Frank Siamese (I am a cat.) <frank@any.net>"
This is TOP SECRET stuff that only Frank can see!!!!!
If anyone else see it, it's the end of the world as we know it.
(With apologies to REM.)
gpg: Signature made Fri 27 Oct 2017 06:39:15 PM EDT using RSA key ID 9FD7014B
gpg: Good signature from "Donald A. Tevault <donniet@something.net>"
frank@ubuntu:~$
没有更多的警告消息,这看起来好多了。在我的端,我会用弗兰克的公钥做同样的事情。
这里非常酷的是,即使整个世界都有我的公钥,对于不是我消息指定接收者的人来说,它是无用的。
在 Ubuntu 机器上,要摆脱gpg-agent is not available in this session
的消息,并且能够在钥匙链中缓存您的密码,安装gnupg-agent
软件包:
sudo apt install gnupg-agent
签署文件而不加密
如果一个文件不是机密的,但你仍然需要确保真实性和完整性,你可以只对它进行签名而不加密:
donnie@ubuntu:~$ gpg -s not_secret_for_frank.txt
You need a passphrase to unlock the secret key for
user: "Donald A. Tevault <donniet@something.net>"
2048-bit RSA key, ID 9FD7014B, created 2017-10-27
gpg: gpg-agent is not available in this session
donnie@ubuntu:~$ ls -l
. . .
-rw-rw-r-- 1 donnie donnie 40 Oct 27 19:30 not_secret_for_frank.txt
-rw-rw-r-- 1 donnie donnie 381 Oct 27 19:31 not_secret_for_frank.txt.gpg
就像以前一样,我创建了一个.gpg
版本的文件。当弗兰克收到文件时,他可能会尝试用less
打开它:
frank@ubuntu:~$ less not_secret_for_frank.txt.gpg
"not_secret_for_frank.txt.gpg" may be a binary file. See it anyway?
<A3>^A^Av^A<89><FE><90>^M^C^@^B^A<88>o3W<9F><D7>^AK^A<AC>Fb^Xnot_secret_for_frank.txtY<F3><C1><C0>This isn't secret, so I just signed it.
<89>^A^\^D^@^A^B^@^F^E^BY<F3><C1><C0>^@
^P<88>o3W<9F><D7>^AK6<AF>^G<FF>Bs<9A>^Lc^@<E9><ED><C2>-2<AE><A7><DF>ͺaB
<EC>/[:<D1>{<B2><FD>o8<C6><C9>x<FE>*4^D<CD>^G^O^F<F3>@v<87>_1<D0>^Bp<FE>q^N3<B0><BE><85><D2>9]{<D6><EF><9A><D8> `<C2><E4>^NC<9B> "Ձ^?M<89>s<9F>z^B"<DF>
s}`<A4>:<B4>&<F7><F4>\EjȰ!^Q <9C>6^E|H<E2>ESC<D9>9<DC>p_ӞESCB<DE>^P<FF>i<CA>)^O
<A0> <CB><C4>+<81><F5><A7>`5<90><BF>Y<DE><FF><<A0>z<BC><BD>5<C5><E8><FE>>
<B7><A2>^L^_^D<DD>Kk<E0><9A>8<C6>S^E<D0>fjz<B2>&G<A4><A8>^Lg$8Q>{<FF><FA>^M_A
<A1><93><C3>4<DC><C4>x<86><D9>^]- <8A> F0<87><8A><94>%A<96><DF><CD>C><80><C3>l
<D3>K<E5>^G<8E><90>d<8C><DA>Aɱb<86><89><DA>S<B6><91><D8><D2><E0><B3>K<FC><9E>
<ED>^@*<EF>x<E7>jø<FD><D3><FA><9A>^]
not_secret_for_frank.txt.gpg (END)
那里有很多无意义的东西,因为签名的缘故,但是如果你仔细看,你会看到明文,未加密的消息。弗兰克将使用gpg
和--verify
选项来验证签名是否真的属于我:
frank@ubuntu:~$ gpg --verify not_secret_for_frank.txt.gpg
gpg: Signature made Fri 27 Oct 2017 07:31:12 PM EDT using RSA key ID 9FD7014B
gpg: Good signature from "Donald A. Tevault <donniet@something.net>"
frank@ubuntu:~$
使用 Linux 统一密钥设置(LUKS)对分区进行加密
能够加密单个文件可能很方便,但对于大量文件来说可能会很笨拙。为此,我们需要更好的东西,我们有三种不同的方法:
-
块加密:我们可以用它来进行整个磁盘加密,或者加密单个分区
-
文件级加密:我们会用这个来加密单个目录,而不必加密底层分区
-
容器化加密:使用不随任何 Linux 发行版捆绑的第三方软件,我们可以创建加密的跨平台容器,可以在 Linux、Mac 或 Windows 机器上打开
Linux 统一密钥设置(LUKS)属于第一类。它内置在几乎每个 Linux 发行版中,使用方法对每个发行版都是一样的。对于我们的演示,我将使用 CentOS 虚拟机,因为 LUKS 现在是 Red Hat Enterprise Linux 7 和 CentOS 7 的默认加密机制。
在操作系统安装期间进行磁盘加密
当您安装 Red Hat Enterprise Linux 7 或其衍生产品之一时,您可以选择加密驱动器。您所需做的就是点击复选框:
除此之外,我只需让安装程序创建默认的分区方案,这意味着/
文件系统和swap
分区都将是逻辑卷。(我将在下一步中介绍。)
在安装继续之前,我必须创建一个密码来挂载加密磁盘:
现在,每当我重新启动系统时,我需要输入这个密码:
一旦机器启动运行,我可以查看逻辑卷的列表。我看到了/
逻辑卷和swap
逻辑卷:
[donnie@localhost etc]$ sudo lvdisplay
--- Logical volume ---
LV Path /dev/centos/swap
LV Name swap
VG Name centos
LV UUID tsme2v-uy87-uech-vpNp-W4E7-fHLf-3bf817
LV Write Access read/write
LV Creation host, time localhost, 2017-10-28 13:00:11 -0400
LV Status available
# open 2
LV Size 2.00 GiB
Current LE 512
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:2
--- Logical volume ---
LV Path /dev/centos/root
LV Name root
VG Name centos
LV UUID MKXVO9-X8fo-w2FC-LnGO-GLnq-k2Xs-xI1gn0
LV Write Access read/write
LV Creation host, time localhost, 2017-10-28 13:00:12 -0400
LV Status available
# open 1
LV Size 17.06 GiB
Current LE 4368
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:1
[donnie@localhost etc]$
我可以查看物理卷的列表。(实际上,列表中只有一个物理卷,并且被列为luks
物理卷。)
[donnie@localhost etc]$ sudo pvdisplay
--- Physical volume ---
PV Name /dev/mapper/luks-2d7f02c7-864f-42ce-b362-50dd830d9772
VG Name centos
PV Size <19.07 GiB / not usable 0
Allocatable yes
PE Size 4.00 MiB
Total PE 4881
Free PE 1
Allocated PE 4880
PV UUID V50E4d-jOCU-kVRn-67w9-5zwR-nbwg-4P725S
[donnie@localhost etc]$
这显示了底层物理卷已加密,这意味着/
和swap
逻辑卷也被加密。这是件好事,因为将交换空间留未加密——在手动设置磁盘加密时常见的错误——可能导致数据泄露。
使用 LUKS 添加加密分区
有时您可能需要向现有机器添加另一个加密驱动器,或者加密便携设备,比如 USB 存储设备。这个过程适用于这两种情况。
为了演示,我将关闭我的 CentOS 虚拟机并添加另一个虚拟驱动器:
我将把驱动器容量增加到 20GB,这样我就有足够的空间可以使用:
重新启动机器后,我现在有了一个/dev/sdb
驱动器可以使用。我的下一步是创建一个分区。无论我创建一个新潮的 GPT 分区还是一个老式的 MBR 分区都无所谓。我将创建一个 GPT 分区,我偏好的工具是gdisk
,因为它与我所熟悉和喜爱的旧fdisk
非常相似。唯一的问题是gdisk
在 CentOS 上默认未安装:
sudo yum install gdisk
sudo gdisk /dev/sdb
我将使用整个驱动器进行分区,并将分区类型设置为默认的8300
。现在我有了/dev/sdb1
分区:
[donnie@localhost ~]$ sudo gdisk -l /dev/sdb
[sudo] password for donnie:
GPT fdisk (gdisk) version 0.8.6
Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present
Found valid GPT with protective MBR; using GPT.
Disk /dev/sdb: 43978112 sectors, 21.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): DC057EC6-3BA8-4269-ABE9-2A28B4FDC84F
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 43978078
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)
Number Start (sector) End (sector) Size Code Name
1 2048 43978078 21.0 GiB 8300 Linux filesystem
[donnie@localhost ~]$
接下来,我将使用cryptsetup
将分区转换为 LUKS 格式。在这个命令中,-v
表示详细模式,-y
表示我需要两次输入密码来正确验证。请注意,当它说要全部大写输入yes
时,它确实意味着要全部大写输入:
[donnie@localhost ~]$ sudo cryptsetup -v -y luksFormat /dev/sdb1
WARNING!
========
This will overwrite data on /dev/sdb1 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase:
Verify passphrase:
Command successful.
[donnie@localhost ~]$
虽然我不必这样做,但我想查看一下我的新加密分区的信息:
[donnie@localhost ~]$ sudo cryptsetup luksDump /dev/sdb1
LUKS header information for /dev/sdb1
Version: 1
Cipher name: aes
Cipher mode: xts-plain64
Hash spec: sha256
. . .
. . .
输出的内容远比我能展示的要多,但您已经有了大致的了解。
接下来,我将把分区映射到设备名称。您可以随意命名设备,我会把我的命名为secrets
。(我知道,这是一个陈腐的名字。您可能不想让您存储秘密的地方显得那么明显。):
[donnie@localhost ~]$ sudo cryptsetup luksOpen /dev/sdb1 secrets
Enter passphrase for /dev/sdb1:
[donnie@localhost ~]$
当我查看/dev/mapper
目录时,我看到了我的新secrets
设备,列为指向dm-3
设备的符号链接:
[donnie@localhost mapper]$ pwd
/dev/mapper
[donnie@localhost mapper]$ ls -l se*
lrwxrwxrwx. 1 root root 7 Oct 28 17:39 secrets -> ../dm-3
[donnie@localhost mapper]$
我将使用dmsetup
查看有关我的新设备的信息:
[donnie@localhost mapper]$ sudo dmsetup info secrets
[sudo] password for donnie:
Name: secrets
State: ACTIVE
Read Ahead: 8192
Tables present: LIVE
Open count: 0
Event number: 0
Major, minor: 253, 3
Number of targets: 1
UUID: CRYPT-LUKS1-6cbdce1748d441a18f8e793c0fa7c389-secrets
[donnie@localhost mapper]$
下一步是以通常的方式格式化分区。我可以使用 Red Hat 和 CentOS 支持的任何文件系统。但是,由于我系统上的其他所有内容都已经使用 XFS 格式化,所以我也会选择 XFS:
[donnie@localhost ~]$ sudo mkfs.xfs /dev/mapper/secrets
meta-data=/dev/mapper/secrets isize=512 agcount=4, agsize=1374123 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=5496491, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2683, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
[donnie@localhost ~]$
我的最后一步是创建一个挂载点并挂载加密分区:
[donnie@localhost ~]$ sudo mkdir /secrets
[sudo] password for donnie:
[donnie@localhost ~]$ sudo mount /dev/mapper/secrets /secrets
[donnie@localhost ~]$
mount
命令将验证分区是否正确挂载:
[donnie@localhost ~]$ mount | grep 'secrets'
/dev/mapper/secrets on /secrets type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
[donnie@localhost ~]$
配置 LUKS 分区以自动挂载
拼图中唯一缺失的部分是配置系统在启动时自动挂载 LUKS 分区。为此,我将配置两个不同的文件:
-
/etc/crypttab
-
/etc/fstab
如果我在安装操作系统时没有选择加密磁盘,我将没有crypttab
文件,必须自己创建。但是,由于我选择加密驱动器,我已经有了一个包含有关该驱动器信息的文件:
luks-2d7f02c7-864f-42ce-b362-50dd830d9772 UUID=2d7f02c7-864f-42ce-b362-50dd830d9772 none
前两个字段描述了加密分区的名称和位置。第三个字段是加密密码。如果设置为none
,就像这里一样,那么密码将在启动时手动输入。
在fstab
文件中,我们有实际挂载分区的条目:
/dev/mapper/centos-root / xfs defaults,x-systemd.device-timeout=0 0 0
UUID=9f9fbf9c-d046-44fc-a73e-ca854d0ca718 /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults,x-systemd.device-timeout=0 0 0
嗯,在这种情况下实际上有两个条目,因为我有两个逻辑卷,/
和swap
,位于我的加密物理卷之上。UUID
行是/boot
分区,这是驱动器中唯一未加密的部分。现在,让我们添加我们的新加密分区,以便它会自动挂载。
这是一个极其有用的地方,可以从桌面主机远程登录到虚拟机。通过使用 GUI 类型的终端,无论是来自 Linux 或 MacOS 机器的终端,还是来自 Windows 机器的 Cygwin,您都可以执行复制和粘贴操作,而如果直接从虚拟机终端工作,则无法执行这些操作。(相信我,您不想输入那些长长的 UUID。)
第一步是获取加密分区的 UUID:
[donnie@localhost etc]$ sudo cryptsetup luksUUID /dev/sdb1
[sudo] password for donnie:
6cbdce17-48d4-41a1-8f8e-793c0fa7c389
[donnie@localhost etc]$
我会复制该 UUID,并将其粘贴到/etc/crypttab
文件中。(请注意,您将粘贴两次。第一次,您将在其前面加上luks-
,第二次您将在其后面加上UUID=
。)
luks-2d7f02c7-864f-42ce-b362-50dd830d9772 UUID=2d7f02c7-864f-42ce-b362-50dd830d9772 none
luks-6cbdce17-48d4-41a1-8f8e-793c0fa7c389 UUID=6cbdce17-48d4-41a1-8f8e-793c0fa7c389 none
最后,我将编辑/etc/fstab
文件,为我的新加密分区添加文件的最后一行。(请注意,我再次使用了luks-
,后跟 UUID 号码。)
/dev/mapper/centos-root / xfs defaults,x-systemd.device-timeout=0 0 0
UUID=9f9fbf9c-d046-44fc-a73e-ca854d0ca718 /boot xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults,x-systemd.device-timeout=0 0 0
/dev/mapper/luks-6cbdce17-48d4-41a1-8f8e-793c0fa7c389 /secrets xfs defaults 0 0
在编辑fstab
文件以添加普通的未加密分区时,我总是喜欢执行sudo mount -a
来检查fstab
文件中是否有拼写错误。但是,对于 LUKS 分区,这是行不通的,因为mount
在系统读取crypttab
文件之前不会识别分区,而这将在我重新启动机器之前不会发生。因此,在添加 LUKS 分区时,请务必格外小心编辑fstab
。
现在到了真相的时刻。我将重新启动机器,看看是否一切正常。
好的,机器已经重新启动,mount
显示我的努力取得了成功:
[donnie@localhost ~]$ mount | grep 'secrets'
/dev/mapper/luks-6cbdce17-48d4-41a1-8f8e-793c0fa7c389 on /secrets type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
[donnie@localhost ~]$
使用 eCryptfs 加密目录
加密整个分区很酷,但有时您可能只需要加密单个目录。为此,我们可以使用 eCryptfs。我们需要使用我们的 Ubuntu 机器进行此操作,因为 Red Hat 和 CentOS 在其产品的第 7 版中不再包括 eCryptfs。(它在 Red Hat 6 和 CentOS 6 中,但在第 7 版中甚至不再可用于安装。)
Ubuntu 安装期间的家目录和磁盘加密
当您安装 Ubuntu 服务器时,您有两次机会实施加密。您首先有机会加密您的家目录:
稍后,在分区磁盘屏幕上,您将有机会为整个磁盘加密逻辑卷:
选择此选项后,您将被要求输入密码:
磁盘加密使用 LUKS,与我们在 CentOS 机器上看到的一样。要证明这一点,我们只需在/etc
目录中查找填充的crypttab
文件:
donnie@ubuntu3:~$ cd /etc
donnie@ubuntu3:/etc$ cat crypttab
sda5_crypt UUID=56190c2b-e46b-40a9-af3c-4cb26c4fe998 none luks,discard
cryptswap1 UUID=60661042-0dbd-4c2a-9cf9-7f02a73864ae /dev/urandom swap,offset=1024,cipher=aes-xts-plain64
donnie@ubuntu3:/etc$
与 Red Hat 和 CentOS 不同,Ubuntu 机器将始终具有/etc/crypttab
文件,即使没有 LUKS 分区。没有 LUKS 分区,该文件将为空。
主目录加密使用 eCryptfs,如/home
目录中的.ecryptfs
目录所示:
donnie@ubuntu3:/home$ ls -la
total 16
drwxr-xr-x 4 root root 4096 Oct 29 15:06 .
drwxr-xr-x 23 root root 4096 Oct 29 15:23 ..
drwx------ 3 donnie donnie 4096 Oct 29 15:29 donnie
drwxr-xr-x 3 root root 4096 Oct 29 15:06 .ecryptfs
donnie@ubuntu3:/home$
所以,我们这里有一个加密叠加加密,双重保护。这真的有必要吗?可能不是,但选择加密我的主目录确保了其访问权限设置为更严格的700
设置,而不是默认的755
设置。但要注意,您现在创建的任何用户帐户都将在其主目录上具有完全开放的权限设置。除非我们选择创建带有加密选项的用户帐户。
为新用户帐户加密主目录
在第二章中,保护用户账户,我向您展示了 Ubuntu 如何允许您在创建用户帐户时加密用户的主目录。让我们回顾一下,看看创建 Goldie 帐户的命令:
sudo adduser --encrypt-home goldie
Goldie 登录时,她首先要做的是unwrap
她的挂载密码,将其写下并存放在安全的地方。(如果她需要恢复损坏的目录,她将需要这个。)
ecryptfs-unwrap-passphrase .ecryptfs/wrapped-passphrase
当您使用adduser --encrypt-home
时,新用户的主目录将自动设置为限制权限值,除了目录所有者,其他人都无法访问。即使您保留adduser.conf
文件的默认设置,也会发生这种情况。
在现有主目录中创建私人目录
假设您有一些用户,出于某种奇怪的原因,不想加密其整个主目录,并且希望保留其主目录上的755
权限设置,以便其他人可以访问其文件。但是,他们还想要一个除了他们自己以外没有人可以访问的私人目录。
任何用户都可以在自己的主目录中创建加密的私人目录,而不是加密整个主目录。如果尚未完成第一步,则需要具有管理员权限的人安装ecryptfs-utils
软件包:
sudo apt install ecryptfs-utils
为了创建这个私人目录,我们将使用交互式的ecryptfs-setup-private
实用程序。如果您有管理员权限,您可以为其他用户执行此操作。没有管理员权限的用户可以为自己执行此操作。对于我们的演示,假设我的大暹罗/灰色虎斑猫 Charlie 需要自己的加密私人空间。(谁知道猫也有秘密,对吧?)
charlie@ubuntu2:~$ ecryptfs-setup-private
Enter your login passphrase [charlie]:
Enter your mount passphrase [leave blank to generate one]:
Enter your mount passphrase (again):
************************************************************************
YOU SHOULD RECORD YOUR MOUNT PASSPHRASE AND STORE IT IN A SAFE LOCATION.
ecryptfs-unwrap-passphrase ~/.ecryptfs/wrapped-passphrase
THIS WILL BE REQUIRED IF YOU NEED TO RECOVER YOUR DATA AT A LATER TIME.
************************************************************************
Done configuring.
Testing mount/write/umount/read...
Inserted auth tok with sig [e339e1ebf3d58c36] into the user session keyring
Inserted auth tok with sig [7a40a176ac647bf0] into the user session keyring
Inserted auth tok with sig [e339e1ebf3d58c36] into the user session keyring
Inserted auth tok with sig [7a40a176ac647bf0] into the user session keyring
Testing succeeded.
Logout, and log back in to begin using your encrypted directory.
charlie@ubuntu2:~$
对于login
密码,Charlie 输入他的正常密码或用于登录用户帐户的密码。他本可以让系统生成自己的mount
密码,但他决定输入自己的密码。由于他输入了自己的挂载密码,他不需要执行ecryptfs-unwrap-passphrase
命令来找出密码是什么。但是,为了展示该命令的工作原理,假设 Charlie 输入TurkeyLips
作为他的挂载密码:
charlie@ubuntu2:~$ ecryptfs-unwrap-passphrase .ecryptfs/wrapped-passphrase
Passphrase:
TurkeyLips
charlie@ubuntu2:~$
是的,这是一个非常弱的密码,但对于我们的演示目的,它有效。
Charlie 注销并重新登录后,他可以开始使用他的新私人目录。此外,您可以看到他的主目录中有三个新的隐藏目录。尽管他的顶级主目录仍然向所有人开放,但这三个新目录只能由 Charlie 访问:
charlie@ubuntu2:~$ ls -la
total 40
drwxr-xr-x 6 charlie charlie 4096 Oct 30 17:00 .
drwxr-xr-x 4 root root 4096 Oct 30 16:38 ..
-rw------- 1 charlie charlie 270 Oct 30 17:00 .bash_history
-rw-r--r-- 1 charlie charlie 220 Aug 31 2015 .bash_logout
-rw-r--r-- 1 charlie charlie 3771 Aug 31 2015 .bashrc
drwx------ 2 charlie charlie 4096 Oct 30 16:39 .cache
drwx------ 2 charlie charlie 4096 Oct 30 16:57 .ecryptfs
drwx------ 2 charlie charlie 4096 Oct 30 16:57 Private
drwx------ 2 charlie charlie 4096 Oct 30 16:57 .Private
-rw-r--r-- 1 charlie charlie 655 May 16 08:49 .profile
charlie@ubuntu2:~$
在/etc/pam.d
目录中执行grep 'ecryptfs' *
命令,您将看到 PAM 配置为在用户登录系统时自动挂载其加密目录:
donnie@ubuntu2:/etc/pam.d$ grep 'ecryptfs' *
common-auth:auth optional pam_ecryptfs.so unwrap
common-password:password optional pam_ecryptfs.so
common-session:session optional pam_ecryptfs.so unwrap
common-session-noninteractive:session optional pam_ecryptfs.so unwrap
donnie@ubuntu2:/etc/pam.d$
使用 eCryptfs 加密其他目录
使用ecryptfs
文件系统挂载其他目录非常简单。对于我们的示例,让我们在我们的文件系统的顶层创建一个secrets
目录,并对其进行加密。请注意,您需要两次列出目录名称,因为您还需要指定挂载点。(基本上,您使用要挂载的目录作为其自己的挂载点。)
sudo mkdir /secrets
sudo mount -t ecryptfs /secrets /secrets
此命令的输出有点冗长,所以让我们分解一下。
首先,您将输入所需的密码,选择加密算法和密钥长度:
donnie@ubuntu2:~$ sudo mount -t ecryptfs /secrets /secrets
[sudo] password for donnie:
Passphrase:
Select cipher:
1) aes: blocksize = 16; min keysize = 16; max keysize = 32
2) blowfish: blocksize = 8; min keysize = 16; max keysize = 56
3) des3_ede: blocksize = 8; min keysize = 24; max keysize = 24
4) twofish: blocksize = 16; min keysize = 16; max keysize = 32
5) cast6: blocksize = 16; min keysize = 16; max keysize = 32
6) cast5: blocksize = 8; min keysize = 5; max keysize = 16
Selection [aes]:
Select key bytes:
1) 16
2) 32
3) 24
Selection [16]:
我们将选择默认的aes
,并使用 16 字节的密钥。
我将选择“明文传递”的默认选项为否,并选择文件名加密为是:
Enable plaintext passthrough (y/n) [n]:
Enable filename encryption (y/n) [n]: y
我将使用默认的“文件名加密密钥”,并验证挂载选项:
Filename Encryption Key (FNEK) Signature [e339e1ebf3d58c36]:
Attempting to mount with the following options:
ecryptfs_unlink_sigs
ecryptfs_fnek_sig=e339e1ebf3d58c36
ecryptfs_key_bytes=16
ecryptfs_cipher=aes
ecryptfs_sig=e339e1ebf3d58c36
此警告仅在您首次挂载目录时出现。对于最后两个问题,我将输入“是”以防止再次出现该警告:
WARNING: Based on the contents of [/root/.ecryptfs/sig-cache.txt],
it looks like you have never mounted with this key
before. This could mean that you have typed your
passphrase wrong.
Would you like to proceed with the mount (yes/no)? : yes
Would you like to append sig [e339e1ebf3d58c36] to
[/root/.ecryptfs/sig-cache.txt]
in order to avoid this warning in the future (yes/no)? : yes
Successfully appended new sig to user sig cache file
Mounted eCryptfs
donnie@ubuntu2:~$
只是为了好玩,我将在我的新加密secrets
目录中创建一个文件,然后卸载该目录:
cd /secrets
sudo vim secret_stuff.txt
cd
sudo umount /secrets
ls -l /secrets
donnie@ubuntu2:/secrets$ ls -l
total 12
-rw-r--r-- 1 root root 12288 Oct 31 18:24 ECRYPTFS_FNEK_ENCRYPTED.FXbXCS5fwxKABUQtEPlumGPaN-RGvqd13yybkpTr1eCVWVHdr-lrmi1X9Vu-mLM-A-VeqIdN6KNZGcs-
donnie@ubuntu2:/secrets$
通过选择加密文件名,当目录未挂载时,没有人甚至可以知道您有哪些文件。当我准备再次访问我的加密文件时,我只需像以前一样重新挂载目录。
使用 eCryptfs 加密交换分区
如果您只是使用 eCryptfs 加密单个目录而不是使用 LUKS 整个磁盘加密,您需要加密交换分区以防止意外数据泄漏。修复这个问题只需要一个简单的命令:
donnie@ubuntu:~$ sudo ecryptfs-setup-swap
[sudo] password for donnie:
WARNING:
An encrypted swap is required to help ensure that encrypted files are not leaked to disk in an unencrypted format.
HOWEVER, THE SWAP ENCRYPTION CONFIGURATION PRODUCED BY THIS PROGRAM WILL BREAK HIBERNATE/RESUME ON THIS SYSTEM!
NOTE: Your suspend/resume capabilities will not be affected.
Do you want to proceed with encrypting your swap? [y/N]: y
INFO: Setting up swap: [/dev/sda5]
WARNING: Commented out your unencrypted swap from /etc/fstab
swapon: stat of /dev/mapper/cryptswap1 failed: No such file or directory
donnie@ubuntu:~$
不要在意关于缺少/dev/mapper/cryptswap1
文件的警告。下次重新启动机器时,它将被创建。
使用 VeraCrypt 进行加密容器的跨平台共享
从前,有一个叫 TrueCrypt 的跨平台程序,允许在不同操作系统之间共享加密容器。但该项目一直笼罩着神秘色彩,因为其开发人员从未透露过自己的身份。然后,突然之间,开发人员发布了一条神秘的消息,称 TrueCrypt 不再安全,并关闭了该项目。
VeraCrypt 是 TrueCrypt 的继任者,它允许在 Linux、Windows、MacOS 和 FreeBSD 机器之间共享加密容器。尽管 LUKS 和 eCryptfs 都不错,但在某些方面 VeraCrypt 确实提供了更多的灵活性:
-
提到的是,VeraCrypt 提供跨平台共享,而 LUKS 和 eCryptfs 则不提供
-
VeraCrypt 允许您加密整个分区或整个存储设备,或创建虚拟加密磁盘
-
VeraCrypt 不仅可以创建加密卷,还可以隐藏它们,从而具有合理的否认性
-
VeraCrypt 有命令行和 GUI 两种变体,因此适用于服务器使用或休闲桌面用户
-
像 LUKS 和 eCryptfs 一样,VeraCrypt 是免费开源软件,这意味着它可以免费使用,并且可以审核源代码以查找错误或后门
获取并安装 VeraCrypt
VeraCrypt 的 Linux 版本是一组通用安装脚本,应该适用于任何 Linux 发行版。在提取.tar.bz2
存档文件后,您将看到两个用于 GUI 安装的脚本和两个用于控制台模式安装的脚本。其中一个用于 32 位 Linux,另一个用于 64 位 Linux:
donnie@linux-0ro8:~/Downloads> ls -l vera*
-r-xr-xr-x 1 donnie users 2976573 Jul 9 05:10 veracrypt-1.21-setup-console-x64
-r-xr-xr-x 1 donnie users 2967950 Jul 9 05:14 veracrypt-1.21-setup-console-x86
-r-xr-xr-x 1 donnie users 4383555 Jul 9 05:08 veracrypt-1.21-setup-gui-x64
-r-xr-xr-x 1 donnie users 4243305 Jul 9 05:13 veracrypt-1.21-setup-gui-x86
-rw-r--r-- 1 donnie users 14614830 Oct 31 23:49 veracrypt-1.21-setup.tar.bz2
donnie@linux-0ro8:~/Downloads>
对于服务器演示,我使用scp
将 64 位控制台模式安装程序传输到我的 Ubuntu 虚拟机之一。可执行权限已经设置,因此安装只需执行以下操作:
donnie@ubuntu:~$ ./veracrypt-1.21-setup-console-x64
您需要 sudo 权限,但安装程序将提示您输入 sudo 密码。阅读并同意相当冗长的许可协议后,安装只需要几秒钟。
在控制台模式下创建和挂载 VeraCrypt 卷
我找不到 VeraCrypt 控制台模式的任何文档,但您可以通过键入veracrypt
来查看可用命令的列表。在此演示中,我在自己的主目录中创建了一个 2GB 的加密卷。但您也可以在其他地方轻松完成,比如在 USB 存储设备上。
要创建新的加密卷,请键入:
veracrypt -c
这将带您进入一个易于使用的交互式实用程序。在大多数情况下,接受默认选项即可。
donnie@ubuntu:~$ veracrypt -c
Volume type:
1) Normal
2) Hidden
Select [1]:
Enter volume path: /home/donnie/good_stuff
Enter volume size (sizeK/size[M]/sizeG): 2G
Encryption Algorithm:
1) AES
2) Serpent
3) Twofish
4) Camellia
5) Kuznyechik
6) AES(Twofish)
7) AES(Twofish(Serpent))
8) Serpent(AES)
9) Serpent(Twofish(AES))
10) Twofish(Serpent)
Select [1]:
Hash algorithm:
1) SHA-512
2) Whirlpool
3) SHA-256
4) Streebog
Select [1]:
. . .
. . .
对于文件系统,默认的 FAT 选项将为你提供 Linux、MacOS 和 Windows 之间最好的跨平台兼容性:
Filesystem:
1) None
2) FAT
3) Linux Ext2
4) Linux Ext3
5) Linux Ext4
6) NTFS
7) exFAT
Select [2]:
然后,你会选择你的密码和 PIM,PIM 代表个人迭代乘数。(对于 PIM,我输入了8891
。高 PIM 值可以提供更好的安全性,但也会导致卷需要更长时间来挂载。)然后,至少输入 320 个随机字符以生成加密密钥。(这时,如果我的猫走过我的键盘会很方便。)
Enter password:
Re-enter password:
Enter PIM: 8891
Enter keyfile path [none]:
Please type at least 320 randomly chosen characters and then press Enter:
按下Enter后,请耐心等待,因为加密卷的最终生成将需要一些时间。在这里,你可以看到我的 2GB 的good_stuff
容器已经成功创建:
donnie@ubuntu:~$ ls -l good_stuff
-rw------- 1 donnie donnie 2147483648 Nov 1 17:02 good_stuff
donnie@ubuntu:~$
要使用这个容器,我必须挂载它。我将首先创建一个挂载点目录;与挂载普通分区一样:
donnie@ubuntu:~$ mkdir good_stuff_dir
donnie@ubuntu:~$
使用veracrypt
实用程序将你的容器挂载到这个挂载点上:
donnie@ubuntu:~$ veracrypt good_stuff good_stuff_dir
Enter password for /home/donnie/good_stuff:
Enter PIM for /home/donnie/good_stuff: 8891
Enter keyfile [none]:
Protect hidden volume (if any)? (y=Yes/n=No) [No]:
Enter your user password or administrator password:
donnie@ubuntu:~$
要查看你已经挂载的 VeraCrypt 卷,使用veracrypt -l
:
donnie@ubuntu:~$ veracrypt -l
1: /home/donnie/secret_stuff /dev/mapper/veracrypt1 /home/donnie/secret_stuff_dir
2: /home/donnie/good_stuff /dev/mapper/veracrypt2 /home/donnie/good_stuff_dir
donnie@ubuntu:~$
就是这样。
在 GUI 模式下使用 VeraCrypt
任何受支持的操作系统的桌面用户都可以安装 VeraCrypt 的 GUI 变体。但要注意,你不能在同一台机器上安装控制台模式变体和 GUI 模式变体,因为其中一个会覆盖另一个。在这里,你可以看到 GUI 版本在我的 CentOS 7 虚拟机上运行:
由于本书的主要重点是服务器安全,我不会在这里详细介绍 GUI 版本。但是,它相当简单易懂,你可以在他们的网站上查看完整的 VeraCrypt 文档。
你可以从这里获取 VeraCrypt:www.veracrypt.fr/en/Home.html
在本章的其余部分,我们将把注意力转向通过锁定 Secure Shell 来保护传输数据的主题。
确保 SSH 协议 1 已禁用
在你的 Linux 职业生涯的这个阶段,你应该已经知道如何使用安全 Shell,或者 SSH,进行远程登录和远程文件传输。你可能不知道的是,SSH 的默认配置实际上是相当不安全的。
SSH 协议版本 1,原始的 SSH 协议,存在严重缺陷,不应该使用。它仍然存在于大多数 Linux 发行版中,但幸运的是,默认情况下它总是被禁用的。但是,如果你打开/etc/ssh/sshd_config
文件并看到这个:
Protocol 1
或者这样:
Protocol 1, 2
然后你会遇到问题。
Ubuntu sshd_config
文件的主页表示,协议版本 1 仍然可用于与传统设备
一起使用。但是,如果你仍在使用那么老的设备,你需要开始认真考虑进行一些升级。
随着 Linux 发行版的更新,你会看到 SSH 协议 1 逐渐被完全移除,就像 Red Hat 和 CentOS 7.4 一样。
创建和管理无密码登录的密钥
安全 Shell 套件,或者 SSH,是一套提供与远程服务器进行安全加密通信的工具。你可以使用 SSH 组件远程登录到远程机器的命令行,你也可以使用scp
或sftp
来安全地传输文件。使用任何这些 SSH 组件的默认方式是使用一个人的普通 Linux 用户帐户的用户名和密码。因此,从我的 OpenSUSE 工作站的终端登录到远程机器看起来是这样的:
donnie@linux-0ro8:~> ssh donnie@192.168.0.8
donnie@192.168.0.8's password:
虽然用户名和密码以加密格式通过网络传输是真实的,这使得恶意行为者难以拦截,但这仍然不是最安全的做法。问题在于攻击者可以访问自动化工具,对 SSH 服务器执行暴力密码攻击。像 Hail Mary Cloud 这样的僵尸网络在互联网上进行持续扫描,以找到启用 SSH 的面向互联网的服务器。如果僵尸网络发现服务器允许通过用户名和密码访问 SSH,它将发起暴力密码攻击。遗憾的是,这种攻击已经成功了很多次,特别是当服务器运营商允许 root 用户通过 SSH 登录时。
这篇较旧的文章详细介绍了 Hail Mary Cloud 僵尸网络:futurismic.com/2009/11/16/the-hail-mary-cloud-slow-but-steady-brute-force-password-guessing-botnet/
在下一节中,我们将看两种方法来帮助防止这些类型的攻击:
-
通过交换公钥启用 SSH 登录
-
禁用通过 SSH 登录的 root 用户
创建用户的 SSH 密钥集
每个用户都有能力创建自己的私钥和公钥。无论用户的客户端机器运行 Linux、MacOS 还是 Windows 上的 Cygwin,在这三种情况下,程序都是完全相同的。为了演示,我将在我的 OpenSUSE 工作站上创建密钥,并将公钥传输到我的一个虚拟机。我使用哪个虚拟机并不重要,但由于我最近没有给 CentOS 机器太多关注,所以我会使用它。
我将从在我的 OpenSUSE 工作站上创建密钥开始:
donnie@linux-0ro8:~> ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/donnie/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/donnie/.ssh/id_rsa.
Your public key has been saved in /home/donnie/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:oqDpCvAptbE8srN6Z4FNXxgkhPhjh1sEKazfMpxhVI8 donnie@linux-0ro8
The key's randomart image is:
+---[RSA 2048]----+
|...*+.. |
|o.+ .+. |
|.+ oE .o |
|. B + . . |
|.=+% ...S |
|.*O*+... |
|* Bo.. |
|++..o |
|B= o |
+----[SHA256]-----+
donnie@linux-0ro8:~>
您可以创建几种不同类型的密钥,但默认的 2048 位 RSA 密钥被认为对可预见的未来足够强大。私钥和公钥 SSH 密钥的工作方式与我们在 GPG 中看到的相同。您将保留私钥,但如果愿意,可以与世界共享公钥。不过,在这种情况下,我只会与一个服务器共享我的公钥。
当要求输入密钥的位置和名称时,我只需按Enter接受默认值。您可以将私钥留空密码,但这不是推荐的做法。
请注意,如果您选择了密钥文件的替代名称,您需要键入整个路径才能使事情正常工作。例如,在我的情况下,我将指定donnie_rsa
密钥的路径为:
/home/donnie/.ssh/donnie_rsa
在我的家目录的.ssh
目录中,我可以看到我创建的密钥:
donnie@linux-0ro8:~/.ssh> ls -l
total 12
-rw------- 1 donnie users 1766 Nov 2 17:52 id_rsa
-rw-r--r-- 1 donnie users 399 Nov 2 17:52 id_rsa.pub
-rw-r--r-- 1 donnie users 2612 Oct 31 18:40 known_hosts
donnie@linux-0ro8:~/.ssh>
id_rsa
密钥是私钥,只有我有读写权限。id_rsa.pub
公钥必须是可读的。
将公钥传输到远程服务器
将我的公钥传输到远程服务器可以让服务器轻松识别我和我的客户端机器。在我可以将公钥传输到远程服务器之前,我需要将私钥添加到我的会话密钥环中。这需要两个命令。(一个命令是调用ssh-agent
,另一个命令实际上将私钥添加到密钥环中。)
donnie@linux-0ro8:~> exec /usr/bin/ssh-agent $SHELL
donnie@linux-0ro8:~> ssh-add
Enter passphrase for /home/donnie/.ssh/id_rsa:
Identity added: /home/donnie/.ssh/id_rsa (/home/donnie/.ssh/id_rsa)
donnie@linux-0ro8:~>
最后,我可以将我的公钥传输到我的 CentOS 服务器,地址为192.168.0.101
:
donnie@linux-0ro8:~> ssh-copy-id donnie@192.168.0.101
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
donnie@192.168.0.101's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'donnie@192.168.0.101'"
and check to make sure that only the key(s) you wanted were added.
donnie@linux-0ro8:~>
下次登录时,我将使用密钥交换,而无需输入密码:
donnie@linux-0ro8:~> ssh donnie@192.168.0.101
Last login: Wed Nov 1 20:11:20 2017
[donnie@localhost ~]$
所以,现在您可能会想:“如果我可以在不输入密码的情况下登录,那么这样安全吗?”答案是,一旦您关闭用于登录的客户端机器的终端窗口,私钥将从您的会话密钥环中删除。当您打开新的终端并尝试登录到远程服务器时,您将看到这个:
donnie@linux-0ro8:~> ssh donnie@192.168.0.101
Enter passphrase for key '/home/donnie/.ssh/id_rsa':
现在,每次我登录到这台服务器时,我都需要输入私钥的密码。(除非我使用前一节中向您展示的两个命令将其添加回会话密钥环中。)
禁用 root 用户登录
几年前,有一个相当引人注目的案例,恶意行为者设法在东南亚某地的许多 Linux 服务器上植入了恶意软件。坏人发现这么做很容易有三个原因:
-
涉及的面向互联网的服务器设置为使用用户名/密码身份验证进行 SSH 登录。
-
允许 root 用户通过 SSH 登录
-
用户密码,包括 root 用户的密码,都非常薄弱
所有这些都意味着 Hail Mary 很容易通过暴力破解方式进入。
不同的发行版对 root 用户登录有不同的默认设置。在您的 CentOS 机器的/etc/ssh/sshd_config
文件中,您将看到这一行:
#PermitRootLogin yes
与大多数配置文件中的情况不同,在sshd_config
中的注释行定义了安全外壳守护程序的默认设置。因此,这一行表示确实允许 root 用户通过 SSH 登录。要更改这一点,我将删除注释符号并将设置更改为no
:
PermitRootLogin no
为了使新设置生效,我将重新启动 SSH 守护程序,在 CentOS 上命名为sshd
,在 Ubuntu 上命名为ssh
:
sudo systemctl restart sshd
在 Ubuntu 机器上,默认设置看起来有点不同:
PermitRootLogin prohibit-password
这意味着允许 root 用户登录,但只能通过公钥交换。如果您确实需要允许 root 用户登录,那可能足够安全。但在大多数情况下,您会希望强制管理员用户使用其普通用户帐户登录,并使用sudo
来满足其管理员需求。因此,在大多数情况下,您仍然可以将此设置更改为no
。
请注意,如果您在 Azure、Rackspace 或 Vultr 等云服务上部署 Ubuntu 服务器实例,服务所有者将要求您使用 root 用户帐户登录到虚拟机。您要做的第一件事是创建自己的普通用户帐户,使用该帐户重新登录,禁用 root 用户帐户,并在sshd_config
中禁用 root 用户登录。
禁用用户名/密码登录
这是您只想在与客户端设置密钥交换后才能做的事情。否则,客户端将无法进行远程登录。
对于 Ubuntu 和 CentOS 机器,查找sshd_config
文件中的此行:
#PasswordAuthentication yes
删除注释符号,将参数值更改为no
,并重新启动 SSH 守护程序。该行现在应该是这样的:
PasswordAuthentication no
现在,当僵尸网络扫描您的系统时,它们会发现进行暴力破解密码攻击是无用的。然后他们会离开并让你独自一人。
为 SFTP 用户设置 chroot 环境
安全文件传输协议(SFTP)是执行安全文件传输的好工具。有一个命令行客户端,但用户最有可能使用图形客户端,如 Filezilla。 SFTP 的一个常见用例是允许网站所有者将网站内容文件上传到 Web 服务器上的适当内容目录。使用默认的 SSH 设置,任何在 Linux 机器上有用户帐户的人都可以通过 SSH 或 SFTP 登录,并可以浏览服务器的整个文件系统。我们真正希望为 SFTP 用户做的是防止他们通过 SSH 登录到命令提示符,并将其限制在其指定的目录中。
创建组并配置 sshd_config 文件
除了用户创建命令略有不同之外,此过程对于 CentOS 或 Ubuntu 都是相同的。因此,您可以使用虚拟机中的任一台来跟随操作。我们将首先创建一个sftpusers
组。
sudo groupadd sftpusers
创建用户帐户,并将其添加到sftpusers
组。我们将一次完成两个操作。在您的 CentOS 机器上,创建 Max 的帐户的命令将是:
sudo useradd -G sftpusers max
在您的 Ubuntu 机器上,它将是:
sudo useradd -m -d /home/max -s /bin/bash -G sftpusers max
在您喜欢的文本编辑器中打开/etc/ssh/sshd_config
文件。找到这一行:
Subsystem sftp /usr/lib/openssh/sftp-server
将其更改为:
Subsystem sftp internal-sftp
此设置允许您禁用某些用户的普通 SSH 登录。
在sshd_config
文件的底部,添加一个Match Group
段落:
Match Group sftpusers
ChrootDirectory /home
AllowTCPForwarding no
AllowAgentForwarding no
X11Forwarding no
ForceCommand internal-sftp
这里一个重要的考虑因素是ChrootDirectory
必须由 root 用户拥有,并且不能被除 root 用户之外的任何人写入。当 Max 登录时,他将在/home
目录中,然后必须cd
进入自己的目录。这也意味着您希望所有用户的主目录都具有限制性的700
权限设置,以防止其他人进入其他人的东西。
保存文件并重新启动 SSH 守护程序。然后,尝试以 Max 的身份通过普通 SSH 登录,只是为了看看会发生什么:
donnie@linux-0ro8:~> ssh max@192.168.0.8
max@192.168.0.8's password:
This service allows sftp connections only.
Connection to 192.168.0.8 closed.
donnie@linux-0ro8:~>
好的,他不能这样做。现在让他尝试通过 SFTP 登录,并验证他是否在/home
目录中:
donnie@linux-0ro8:~> sftp max@192.168.0.8
max@192.168.0.8's password:
Connected to 192.168.0.8.
drwx------ 7 1000 1000 4096 Nov 4 22:53 donnie
drwx------ 5 1001 1001 4096 Oct 27 23:34 frank
drwx------ 3 1003 1004 4096 Nov 4 22:43 katelyn
drwx------ 2 1002 1003 4096 Nov 4 22:37 max
sftp>
现在,让我们看看他是否能够在/home
目录之外进行cd
操作:
sftp> cd /etc
Couldn't stat remote file: No such file or directory
sftp>
因此,我们的 chroot 监狱确实有效。
动手实验-为 sftpusers 组设置 chroot 目录
对于这个实验,您可以使用 CentOS 虚拟机或 Ubuntu 虚拟机。您将添加一个组,然后配置sshd_config
文件,以允许组成员只能通过 SFTP 登录,并将他们限制在自己的目录中。对于模拟的客户端机器,您可以使用您的 MacOS 或 Linux 桌面机器的终端,或者使用您的 Windows 机器上的 Cygwin:
- 创建
sftpusers
组:
sudo groupadd sftpusers
- 为 Max 创建一个用户账户,并将他添加到
sftpusers
组中。在 CentOS 上,执行以下操作:
sudo useradd -G sftpusers max
在 Ubuntu 上,执行以下操作:
sudo useradd -m -d /home/max -s /bin/bash -G sftpusers max
- 对于 Ubuntu,请确保用户的主目录都设置为只有目录的用户具有读取、写入和执行权限。如果不是这种情况,请执行以下操作:
sudo chmod 700 /home/*
- 在您喜欢的文本编辑器中打开
/etc/ssh/sshd_config
文件。找到以下行:
Subsystem sftp /usr/lib/openssh/sftp-server
将其更改为:
Subsystem sftp internal-sftp
- 在
sshd_config
文件的末尾,添加以下段落:
Match Group sftpusers
ChrootDirectory /home
AllowTCPForwarding no
AllowAgentForwarding no
X11Forwarding no
ForceCommand internal-sftp
- 重新启动 SSH 守护程序。在 CentOS 上,执行以下操作:
sudo systemctl sshd restart
在 Ubuntu 上,执行以下操作:
sudo systemctl ssh restart
- 让 Max 尝试通过普通 SSH 登录,看看会发生什么:
ssh max@IP_Address_of_your_vm
- 现在,让 Max 通过 SFTP 登录。一旦他登录,让他尝试从
/home
目录中进行cd
操作:
sftp max@IP_Address_of_your_vm
- 实验结束。
总结
在本章中,我们已经看到如何使用各种加密技术来保护我们的秘密。我们从 GNU Privacy Guard 开始,用于加密单个文件。然后我们转向磁盘、分区和目录加密实用程序。LUKS 和 eCryptfs 专门用于 Linux,但我们也看了 VeraCrypt,它可以在任何主要操作系统上使用。
在下一章中,我们将深入研究自主访问控制的主题。到时候见。
第五章:掌握自主访问控制
自主访问控制,DAC,实际上只意味着每个用户都有能力控制谁可以进入他或她的东西。如果我想打开我的家目录,以便系统上的每个其他用户都可以进入,我可以这样做。这样做后,我可以控制谁可以访问每个特定的文件。在下一章中,我们将使用我们的 DAC 技能来管理共享目录,其中组的成员可能需要对其中的文件有不同级别的访问权限。
到您的 Linux 职业的这一点上,您可能已经了解了通过设置文件和目录权限来控制访问的基础知识。在本章中,我们将回顾基础知识,然后我们将看一些更高级的概念。我们将涵盖的主题包括:
-
使用
chown
更改文件和目录的所有权 -
使用
chmod
在文件和目录上设置权限 -
SUID 和 SGID 设置对我们常规文件有什么作用
-
在不需要它们的文件上设置 SUID 和 SGID 权限的安全影响
-
如何使用扩展文件属性来保护敏感文件
使用 chown 更改文件和目录的所有权
真正控制对文件和目录的访问其实归结为确保适当的用户拥有文件和目录,并且每个文件和目录都以这样的方式设置了权限,以便只有授权用户才能访问它们。chown
实用程序涵盖了这个方程式的第一部分。
关于chown
的一个独特之处是,即使您在自己的目录中处理自己的文件,您也必须具有 sudo 特权才能使用它。您可以使用它来更改文件或目录的用户,与文件或目录关联的组,或同时更改两者。
首先,假设您拥有perm_demo.txt
文件,并且希望将用户和组关联更改为另一个用户。在这种情况下,我将把文件所有权从我更改为 Maggie:
[donnie@localhost ~]$ ls -l perm_demo.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:02 perm_demo.txt
[donnie@localhost ~]$ sudo chown maggie:maggie perm_demo.txt
[donnie@localhost ~]$ ls -l perm_demo.txt
-rw-rw-r--. 1 maggie maggie 0 Nov 5 20:02 perm_demo.txt
[donnie@localhost ~]$
maggie:maggie
中的第一个maggie
是您想要授予所有权的用户。冒号后面的第二个maggie
表示您希望文件关联的组。由于我要同时更改用户和组为maggie
,我可以省略第二个maggie
,只需在冒号后面跟着第一个maggie
,我将获得相同的结果:
sudo chown maggie: perm_demo.txt
只需更改组关联而不更改用户,只需列出组名称,前面加上冒号:
[donnie@localhost ~]$ sudo chown :accounting perm_demo.txt
[donnie@localhost ~]$ ls -l perm_demo.txt
-rw-rw-r--. 1 maggie accounting 0 Nov 5 20:02 perm_demo.txt
[donnie@localhost ~]$
最后,只需更改用户而不更改组,列出用户名而不带冒号:
[donnie@localhost ~]$ sudo chown donnie perm_demo.txt
[donnie@localhost ~]$ ls -l perm_demo.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:02 perm_demo.txt
[donnie@localhost ~]$
这些命令在目录上的工作方式与在文件上的工作方式相同。但是,如果您还想更改目录的内容的所有权和/或组关联,同时也在目录本身上进行更改,请使用-R
选项,表示递归。在这种情况下,我只想将perm_demo_dir
目录的组更改为会计
:
[donnie@localhost ~]$ ls -ld perm_demo_dir
drwxrwxr-x. 2 donnie donnie 74 Nov 5 20:17 perm_demo_dir
[donnie@localhost ~]$ ls -l perm_demo_dir
total 0
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file1.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file2.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file3.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file4.txt
[donnie@localhost ~]$ sudo chown -R :accounting perm_demo_dir
[donnie@localhost ~]$ ls -ld perm_demo_dir
drwxrwxr-x. 2 donnie accounting 74 Nov 5 20:17 perm_demo_dir
[donnie@localhost ~]$ ls -l perm_demo_dir
total 0
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file1.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file2.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file3.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file4.txt
[donnie@localhost ~]$
这就是chown
的全部内容。
使用 chmod 在文件和目录上设置权限值
在 Unix 和 Linux 系统上,您将使用chmod
实用程序在文件和目录上设置权限值。您可以为文件或目录的用户、与文件或目录关联的组以及其他人设置权限。三个基本权限是:
-
r
:这表示读取权限。 -
w
:这是写入权限。 -
x
:这是可执行权限。您可以将其应用于任何类型的程序文件,或者目录。如果您将可执行权限应用于目录,授权的用户将能够cd
进入它。
对文件和目录进行ls -l
,您会看到类似以下内容:
-rw-rw-r--. 1 donnie donnie 804692 Oct 28 18:44 yum_list.txt
这一行的第一个字符表示文件的类型。在这种情况下,我们看到一个破折号,表示一个普通文件。(普通文件基本上是普通用户在日常例行工作中能够访问的各种类型的文件。)接下来的三个字符rw-
表示该文件对用户(即文件所有者)具有读取和写入权限。然后我们看到组的rw-
权限,以及其他人的r--
权限。程序文件还会设置可执行权限:
-rwxr-xr-x. 1 root root 62288 Nov 20 2015 xargs
在这里,我们看到xargs
程序文件为所有人设置了可执行权限。
有两种方法可以使用chmod
来更改权限设置:
-
符号方法
-
数字方法
使用符号方法设置权限
每当您以普通用户身份创建文件时,默认情况下,它将对用户和组具有读取和写入权限,并对其他人具有只读权限。如果您创建一个程序文件,您必须自己添加可执行权限。使用符号方法,您可以使用以下命令之一来执行此操作:
chmod u+x donnie_script.sh
chmod g+x donnie_script.sh
chmod o+x donnie_script.sh
chmod u+x,g+x donnie_script.sh
chmod a+x donnie_script.sh
前三个命令为用户、组和其他人添加可执行权限。第四个命令为用户和组添加可执行权限,最后一个命令为所有人(a
代表所有人)添加可执行权限。您也可以通过用-
替换+
来删除可执行权限。并且,您也可以根据需要添加或删除读取或写入权限。
虽然这种方法有时很方便,但它也有一点缺陷。也就是说,它只能添加已有权限,或者删除已有权限。如果您需要确保特定文件的所有权限都设置为特定值,符号方法可能会变得有些难以掌握。而对于 shell 脚本来说,更是如此。在 shell 脚本中,您需要添加各种额外的代码来确定已设置了哪些权限。数字方法可以极大地简化我们的工作。
使用数字方法设置权限
使用数字方法,您将使用八进制值来表示文件或目录的权限设置。对于r
、w
和x
权限,分别分配数字值4
、2
和1
。对用户、组和其他人的位置进行此操作,然后将它们相加以获得文件或目录的权限值:
用户 | 组 | 其他人 |
---|---|---|
rwx |
rwx |
rwx |
421 |
421 |
421 |
7 |
7 |
7 |
因此,如果您为所有人设置了所有权限,文件或目录的值将为777
。如果我要创建一个 shell 脚本文件,默认情况下,它将具有标准的664
权限,即用户和组具有读取和写入权限,其他人只有只读权限:
-rw-rw-r--. 1 donnie donnie 0 Nov 6 19:18 donnie_script.sh
如果您以 root 权限创建文件,无论是使用 sudo 还是从 root 用户命令提示符,您会发现默认权限设置更为严格,为644
。
假设我想要使这个脚本文件可执行,但我希望是全世界唯一可以对其进行任何操作的人。我可以这样做:
[donnie@localhost ~]$ chmod 700 donnie_script.sh
[donnie@localhost ~]$ ls -l donnie_script.sh
-rwx------. 1 donnie donnie 0 Nov 6 19:18 donnie_script.sh
[donnie@localhost ~]$
通过这个简单的命令,我已经从组和其他人那里删除了所有权限,并为自己设置了可执行权限。这就是数字方法在编写 shell 脚本时如此方便的地方。
一旦您使用数字方法一段时间后,查看文件并确定其数字权限值将变得轻车熟路。与此同时,您可以使用带有-c %a
选项的stat
来显示这些值。例如:
[donnie@localhost ~]$ stat -c %a yum_list.txt
664
[donnie@localhost ~]$
[donnie@localhost ~]$ stat -c %a donnie_script.sh
700
[donnie@localhost ~]$
[donnie@localhost ~]$ stat -c %a /etc/fstab
644
[donnie@localhost ~]$
使用 SUID 和 SGID 设置普通文件的权限
当普通文件设置了 SUID 权限时,访问该文件的人将具有与文件所有者相同的权限。当普通文件设置了 SGID 权限时,访问该文件的人将具有与文件关联的组相同的权限。这在程序文件上特别有用。
为了演示这一点,让我们假设 Maggie,一个普通的、没有特权的用户,想要更改自己的密码。因为这是她自己的密码,她只需使用单词命令passwd
,而不使用sudo
:
[maggie@localhost ~]$ passwd
Changing password for user maggie.
Changing password for maggie.
(current) UNIX password:
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[maggie@localhost ~]$
要更改密码,一个人必须对/etc/shadow
文件进行更改。在我的 CentOS 机器上,shadow 文件的权限看起来像这样:
[donnie@localhost etc]$ ls -l shadow
----------. 1 root root 840 Nov 6 19:37 shadow
[donnie@localhost etc]$
在 Ubuntu 机器上,它们看起来像这样:
donnie@ubuntu:/etc$ ls -l shadow
-rw-r----- 1 root shadow 1316 Nov 4 18:38 shadow
donnie@ubuntu:/etc$
无论如何,权限设置不允许 Maggie 修改 shadow 文件。然而,通过更改她的密码,她可以修改 shadow 文件。那么,到底发生了什么?为了回答这个问题,让我们进入/usr/bin
目录,查看passwd
可执行文件的权限设置:
[donnie@localhost etc]$ cd /usr/bin
[donnie@localhost bin]$ ls -l passwd
-rwsr-xr-x. 1 root root 27832 Jun 10 2014 passwd
[donnie@localhost bin]$
对于用户权限,您会看到rws
而不是rwx
。s
表示该文件设置了 SUID 权限。由于该文件属于 root 用户,访问该文件的任何人都具有与 root 用户相同的权限。我们看到小写s
意味着该文件也为 root 用户设置了可执行权限。由于 root 用户被允许修改 shadow 文件,使用passwd
实用程序来更改自己的密码的人也可以修改 shadow 文件。
设置了 SGID 权限的文件在组的可执行位置上有一个s
:
[donnie@localhost bin]$ ls -l write
-rwxr-sr-x. 1 root tty 19536 Aug 4 07:18 write
[donnie@localhost bin]$
与tty
组关联的write
实用程序允许用户通过他们的命令行控制台向其他用户发送消息。拥有tty
组权限允许用户这样做。
SUID 和 SGID 权限的安全影响
尽管在可执行文件上设置 SUID 或 SGID 权限可能很有用,但我们应该将其视为必要的恶。虽然在某些操作系统文件上设置 SUID 或 SGID 对于 Linux 系统的正常运行至关重要,但当用户在其他文件上设置 SUID 或 SGID 时,它就成为了安全风险。问题在于,如果入侵者找到了属于 root 用户并设置了 SUID 位的可执行文件,他们可以利用它来攻击系统。在离开之前,他们可能会留下自己的属于 root 的文件,并设置 SUID 位,这将使他们很容易地在下次进入系统。如果找不到入侵者的 SUID 文件,即使原始问题得到解决,入侵者仍将有访问权限。
SUID 的数字值为4000
,SGID 的数字值为2000
。要在文件上设置 SUID,您只需将4000
添加到您否则设置的权限值中。例如,如果您有一个权限值为755
的文件,您可以通过将权限值更改为4755
来设置 SUID。(这将为用户提供读/写/执行权限,为组提供读/执行权限,为其他用户提供读/执行权限,并添加 SUID 位。)
查找虚假的 SUID 或 SGID 文件
一个快速的安全技巧是运行find
命令来清点系统上的 SUID 和 SGID 文件。您可以将输出保存到文本文件中,以便在下次运行命令时验证是否添加了任何内容。您的命令看起来会像这样:
sudo find / -type f \( -perm -4000 -o -perm 2000 \) > suid_sgid_files.txt
这是分解:
-
/
:我们正在搜索整个文件系统。由于某些目录只能由具有 root 权限的用户访问,我们需要使用sudo
。 -
-type f
:这意味着我们正在搜索常规文件,这将包括可执行程序文件和 shell 脚本。 -
-perm 4000
:我们正在搜索具有4000
或 SUID 权限位设置的文件。 -
-o
:或操作符。 -
-perm 2000
:我们正在搜索具有2000
或 SGID 权限位设置的文件。 -
>
:当然,我们正在使用>
操作符将输出重定向到suid_sgid_files.txt
文本文件中。
请注意,两个-perm
项需要合并为一个用一对括号括起来的术语。为了防止 Bash shell 错误解释括号字符,我们需要用反斜杠对每个括号进行转义。我们还需要在第一个括号字符和第一个-perm
之间以及2000
和最后一个反斜杠之间放置一个空格。此外,-type f
和-perm
术语之间的 and 运算符被理解为存在,即使没有插入-a
。您创建的文本文件应该看起来像这样:
/usr/bin/chfn
/usr/bin/chsh
/usr/bin/chage
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/mount
/usr/bin/su
/usr/bin/umount
/usr/bin/sudo
/usr/bin/pkexec
/usr/bin/crontab
/usr/bin/passwd
/usr/sbin/pam_timestamp_check
/usr/sbin/unix_chkpwd
/usr/sbin/usernetctl
/usr/lib/polkit-1/polkit-agent-helper-1
/usr/lib64/dbus-1/dbus-daemon-launch-helper
如果您想查看哪些文件是 SUID 和哪些是 SGID 的详细信息,可以添加-ls
选项:
sudo find / -type f \( -perm -4000 -o -perm 2000 \) -ls > suid_sgid_files.txt
现在,假设 Maggie 出于任何原因,决定在她的主目录中的一个 shell 脚本文件上设置 SUID 位:
[maggie@localhost ~]$ chmod 4755 bad_script.sh
[maggie@localhost ~]$ ls -l
total 0
-rwsr-xr-x. 1 maggie maggie 0 Nov 7 13:06 bad_script.sh
[maggie@localhost ~]$
再次运行find
命令,将输出保存到另一个文本文件中。然后,对两个文件进行diff
操作,查看发生了什么变化:
[donnie@localhost ~]$ diff suid_sgid_files.txt suid_sgid_files2.txt
17a18
> /home/maggie/bad_script.sh
[donnie@localhost ~]$
唯一的区别是添加了 Maggie 的 shell 脚本文件。
动手实验-搜索 SUID 和 SGID 文件
您可以在您的任一虚拟机上进行此实验。您将把find
命令的输出保存到一个文本文件中:
- 在整个文件系统中搜索所有具有 SUID 或 SGID 设置的文件,将输出保存到一个文本文件中:
sudo find / -type f \( -perm -4000 -o -perm 2000 \) -ls >
suid_sgid_files.txt
- 登录到系统上的任何其他用户帐户,并创建一个虚拟 shell 脚本文件。然后,在该文件上设置 SUID 权限,并注销到您自己的用户帐户:
su - desired_user_account
touch some_shell_script.sh
chmod 4755 some_shell_script.sh
ls -l some_shell_script.sh
exit
- 再次运行
find
命令,将输出保存到另一个文本文件中:
sudo find / -type f \( -perm -4000 -o -perm 2000 \) -ls >
suid_sgid_files_2.txt
- 查看两个文件之间的区别:
diff suid_sgid_files.txt suid_sgid_files_2.txt
- 实验结束。
防止在分区上使用 SUID 和 SGID
正如我们之前所说,您不希望用户对他们创建的文件分配 SUID 和 SGID,因为这会带来安全风险。您可以通过使用nosuid
选项来阻止在分区上使用 SUID 和 SGID。因此,我在上一章中创建的luks
分区的/etc/fstab
文件条目将如下所示:
/dev/mapper/luks-6cbdce17-48d4-41a1-8f8e-793c0fa7c389 /secrets xfs nosuid 0 0
不同的 Linux 发行版在操作系统安装期间设置默认分区方案的方式不同。大多数情况下,业务的默认方式是将除/boot
目录之外的所有目录都放在/
分区下。如果您要设置自定义分区方案,可以将/home
目录放在自己的分区上,并在那里设置nosuid
选项。请记住,您不希望为/
分区设置nosuid
,否则您将得到一个无法正常运行的操作系统。
使用扩展文件属性保护敏感文件
扩展文件属性是帮助您保护敏感文件的另一个工具。它们不会阻止入侵者访问您的文件,但它们可以帮助您防止敏感文件被更改或删除。有很多扩展属性,但我们只需要查看与文件安全有关的属性。
首先,让我们执行lsattr
命令,查看您已经设置的扩展属性。在 CentOS 机器上,您的输出看起来会像这样:
[donnie@localhost ~]$ lsattr
---------------- ./yum_list.txt
---------------- ./perm_demo.txt
---------------- ./perm_demo_dir
---------------- ./donnie_script.sh
---------------- ./suid_sgid_files.txt
---------------- ./suid_sgid_files2.txt
[donnie@localhost ~]$
到目前为止,我的任何文件上都没有设置扩展属性。
在 Ubuntu 机器上,输出看起来会更像这样:
donnie@ubuntu:~$ lsattr
-------------e-- ./file2.txt
-------------e-- ./secret_stuff_dir
-------------e-- ./secret_stuff_for_frank.txt.gpg
-------------e-- ./good_stuff
-------------e-- ./secret_stuff
-------------e-- ./not_secret_for_frank.txt.gpg
-------------e-- ./file4.txt
-------------e-- ./good_stuff_dir
donnie@ubuntu:~$
我们不用担心e
属性,因为那只意味着分区是用 ext4 文件系统格式化的。CentOS 没有设置该属性,因为其分区是用 XFS 文件系统格式化的。
我们将查看的两个属性是:
-
a
:您可以将文本附加到具有此属性的文件的末尾,但不能覆盖它。只有具有适当 sudo 特权的人才能设置或删除此属性。 -
i
:这使文件不可变,只有具有适当 sudo 特权的人才能设置或删除它。具有此属性的文件无法被删除或以任何方式更改。也不可能创建具有此属性的文件的硬链接。
要设置或删除属性,您将使用chattr
命令。您可以在文件上设置多个属性,但只有在有意义的情况下才能这样做。例如,您不会在同一个文件上同时设置a
和i
属性,因为i
会覆盖a
。
让我们首先创建带有这个文本的perm_demo.txt
文件:
This is Donnie's sensitive file that he doesn't want to have overwritten.
设置a
属性
现在我将设置a
属性:
[donnie@localhost ~]$ sudo chattr +a perm_demo.txt
[sudo] password for donnie:
[donnie@localhost ~]$
您将使用+
来添加属性,使用-
来删除属性。此外,文件属于我,位于我的家目录中也无关紧要。我仍然需要 sudo 权限来添加或删除此属性。
现在,让我们看看当我尝试覆盖这个文件时会发生什么:
[donnie@localhost ~]$ echo "I want to overwrite this file." > perm_demo.txt
-bash: perm_demo.txt: Operation not permitted
[donnie@localhost ~]$ sudo echo "I want to overwrite this file." > perm_demo.txt
-bash: perm_demo.txt: Operation not permitted
[donnie@localhost ~]$
无论是否具有sudo
权限,我都无法覆盖它。那么,如果我尝试向其追加一些内容呢?
[donnie@localhost ~]$ echo "I want to append this to the end of the file." >> perm_demo.txt
[donnie@localhost ~]$
这次没有错误消息。让我们看看文件中现在有什么:
This is Donnie's sensitive file that he doesn't want to have overwritten.
I want to append this to the end of the file.
除了无法覆盖文件之外,我也无法删除它:
[donnie@localhost ~]$ rm perm_demo.txt
rm: cannot remove ‘perm_demo.txt’: Operation not permitted
[donnie@localhost ~]$ sudo rm perm_demo.txt
[sudo] password for donnie:
rm: cannot remove ‘perm_demo.txt’: Operation not permitted
[donnie@localhost ~]$
所以,a
有效。但是,我决定不再设置这个属性,所以我会将其删除:
[donnie@localhost ~]$ sudo chattr -a perm_demo.txt
[donnie@localhost ~]$ lsattr perm_demo.txt
---------------- perm_demo.txt
[donnie@localhost ~]$
设置i
属性
当文件设置了i
属性时,您唯一能做的事情就是查看其内容。您不能更改它,移动它,删除它,重命名它,或者创建硬链接到它。让我们用perm_demo.txt
文件来测试一下:
[donnie@localhost ~]$ sudo chattr +i perm_demo.txt
[donnie@localhost ~]$ lsattr perm_demo.txt
----i----------- perm_demo.txt
[donnie@localhost ~]$
现在,到有趣的部分:
[donnie@localhost ~]$ sudo echo "I want to overwrite this file." > perm_demo.txt
-bash: perm_demo.txt: Permission denied
[donnie@localhost ~]$ echo "I want to append this to the end of the file." >> perm_demo.txt
-bash: perm_demo.txt: Permission denied
[donnie@localhost ~]$ sudo echo "I want to append this to the end of the file." >> perm_demo.txt
-bash: perm_demo.txt: Permission denied
[donnie@localhost ~]$ rm -f perm_demo.txt
rm: cannot remove ‘perm_demo.txt’: Operation not permitted
[donnie@localhost ~]$ sudo rm -f perm_demo.txt
rm: cannot remove ‘perm_demo.txt’: Operation not permitted
[donnie@localhost ~]$ sudo rm -f perm_demo.txt
还有一些命令我可以尝试,但您已经明白了。要删除i
属性,我会执行:
[donnie@localhost ~]$ sudo chattr -i perm_demo.txt
[donnie@localhost ~]$ lsattr perm_demo.txt
---------------- perm_demo.txt
[donnie@localhost ~]$
动手实验 - 设置与安全相关的扩展文件属性
对于这个实验,您将创建一个带有您自己选择的文本的perm_demo.txt
文件。您将设置i
和a
属性,并查看结果:
-
使用您喜欢的文本编辑器,创建带有一行文本的
perm_demo.txt
文件。 -
查看文件的扩展属性:
lsattr perm_demo.txt
- 添加
a
属性:
sudo chattr +a perm_demo.txt
lsattr perm_demo.txt
- 尝试覆盖和删除文件:
echo "I want to overwrite this file." > perm_demo.txt
sudo echo "I want to overwrite this file." > perm_demo.txt
rm perm_demo.txt
sudo rm perm_demo.txt
- 现在,向文件追加一些内容:
echo "I want to append this line to the end of the file." >>
perm_demo.txt
- 删除
a
属性,并添加i
属性:
sudo chattr -a perm_demo.txt
lsattr perm_demo.txt
sudo chattr +i perm_demo.txt
lsattr perm_demo.txt
-
重复第 4 步。
-
另外,尝试更改文件名并创建文件的硬链接:
mv perm_demo.txt some_file.txt
sudo mv perm_demo.txt some_file.txt
ln ~/perm_demo.txt ~/some_file.txt
sudo ln ~/perm_demo.txt ~/some_file.txt
- 现在,尝试创建文件的符号链接:
ln -s ~/perm_demo.txt ~/some_file.txt
请注意,i
属性不允许您创建文件的硬链接,但它将允许您创建符号链接。
- 实验结束。
总结
在本章中,我们回顾了为文件和目录设置所有权和权限的基础知识。然后,我们介绍了当正确使用时 SUID 和 SGID 可以为我们做什么,以及在我们自己的可执行文件上设置它们的风险。最后,我们通过查看处理文件安全的两个扩展文件属性来完成了这一系列。
在下一章中,我们将把我们在这里学到的知识扩展到更高级的文件和目录访问技术。我会在那里见到你。
第六章:访问控制列表和共享目录管理
在上一章中,我们回顾了自主访问控制的基础知识。在本章中,我们将进一步讨论 DAC,探讨一些更高级的技术,让您可以使用 DAC 完全按照您的意愿进行操作。
本章主题包括:
-
为用户或组创建访问控制列表(ACL)
-
为目录创建继承的 ACL
-
通过使用 ACL 掩码删除特定权限
-
使用
tar --acls
选项防止在备份期间丢失 ACL -
创建用户组并向其中添加成员
-
为组创建共享目录,并对其进行适当的权限设置
-
在共享目录上设置 SGID 位和粘着位
-
使用 ACL 仅允许组的某些成员访问共享目录中的文件
为用户或组创建访问控制列表
正常的 Linux 文件和目录权限设置还可以,但它们不够精细。通过 ACL,我们可以只允许某个人访问文件或目录,或者我们可以允许多个人访问文件或目录,并为每个人设置不同的权限。如果我们有一个对所有人都开放的文件或目录,我们可以使用 ACL 来允许不同级别的访问,无论是对组还是个人。在本章末尾,我们将把我们学到的知识整合起来,以便为组管理共享目录。
您可以使用getfacl
查看文件或目录的访问控制列表。(请注意,您不能一次查看目录中的所有文件。)首先,让我们使用getfacl
来查看acl_demo.txt
文件上是否已经设置了任何访问控制列表:
[donnie@localhost ~]$ touch acl_demo.txt
[donnie@localhost ~]$ getfacl acl_demo.txt
# file: acl_demo.txt
# owner: donnie
# group: donnie
user::rw-
group::rw-
other::r--
[donnie@localhost ~]$
这里我们只看到正常的权限设置,所以没有 ACL。
设置 ACL 的第一步是从除文件用户之外的所有人那里删除所有权限。这是因为默认权限设置允许组成员具有读/写访问权限,其他人具有读取权限。因此,在不删除这些权限的情况下设置 ACL 将是毫无意义的:
[donnie@localhost ~]$ chmod 600 acl_demo.txt
[donnie@localhost ~]$ ls -l acl_demo.txt
-rw-------. 1 donnie donnie 0 Nov 9 14:37 acl_demo.txt
[donnie@localhost ~]$
使用setfacl
设置 ACL 时,可以允许用户或组具有任何组合的读取、写入或执行权限。在我们的情况下,假设我想让 Maggie 读取文件,并阻止她具有写入或执行权限:
[donnie@localhost ~]$ setfacl -m u:maggie:r acl_demo.txt
[donnie@localhost ~]$ getfacl acl_demo.txt
# file: acl_demo.txt
# owner: donnie
# group: donnie
user::rw-
user:maggie:r--
group::---
mask::r--
other::---
[donnie@localhost ~]$ ls -l acl_demo.txt
-rw-r-----+ 1 donnie donnie 0 Nov 9 14:37 acl_demo.txt
[donnie@localhost ~]$
setfacl
的-m
选项意味着我们将修改 ACL。(在这种情况下创建一个也可以,但没关系。)u:
表示我们正在为用户设置 ACL。然后我们列出用户的名称,后跟另一个冒号,以及我们要授予该用户的权限列表。在这种情况下,我们只允许 Maggie 读取访问。我们通过列出要应用此 ACL 的文件来完成命令。getfacl
输出显示 Maggie 确实具有读取权限。最后,我们在ls -l
输出中看到组被列为具有读取权限,即使我们已经在此文件上设置了600
权限设置。但是,还有一个+
号,这告诉我们该文件具有 ACL。当我们设置 ACL 时,ACL 的权限显示为ls -l
中的组权限。
更进一步,假设我想让 Frank 对此文件具有读/写访问权限:
[donnie@localhost ~]$ setfacl -m u:frank:rw acl_demo.txt
[donnie@localhost ~]$ getfacl acl_demo.txt
# file: acl_demo.txt
# owner: donnie
# group: donnie
user::rw-
user:maggie:r--
user:frank:rw-
group::---
mask::rw-
other::---
[donnie@localhost ~]$ ls -l acl_demo.txt
-rw-rw----+ 1 donnie donnie 0 Nov 9 14:37 acl_demo.txt
[donnie@localhost ~]$
因此,我们可以为同一个文件分配两个或更多不同的 ACL。在ls -l
输出中,我们看到我们已经为组设置了rw
权限,这实际上只是我们在两个 ACL 中设置的权限的总结。
我们可以通过将u:
替换为g:
来为组访问设置 ACL:
[donnie@localhost ~]$ getfacl new_file.txt
# file: new_file.txt
# owner: donnie
# group: donnie
user::rw-
group::rw-
other::r--
[donnie@localhost ~]$ chmod 600 new_file.txt
[donnie@localhost ~]$ setfacl -m g:accounting:r new_file.txt
[donnie@localhost ~]$ getfacl new_file.txt
# file: new_file.txt
# owner: donnie
# group: donnie
user::rw-
group::---
group:accounting:r--
mask::r--
other::---
[donnie@localhost ~]$ ls -l new_file.txt
-rw-r-----+ 1 donnie donnie 0 Nov 9 15:06 new_file.txt
[donnie@localhost ~]$
accounting
组的成员现在可以读取此文件。
为目录创建继承的访问控制列表
有时您可能希望在共享目录中创建的所有文件都具有相同的访问控制列表。我们可以通过将继承的 ACL 应用于目录来实现这一点。尽管,要理解的是,即使这听起来像一个很酷的主意,以正常方式创建文件将导致文件对组设置读/写权限,并对其他用户设置读权限。因此,如果您为用户正常创建文件的目录设置了这一点,您最好希望创建一个 ACL,为某人添加写或执行权限。或者确保用户为他们创建的所有文件设置600
权限设置,假设用户确实需要限制对他们的文件的访问。
另一方面,如果您正在创建一个在特定目录中创建文件的 shell 脚本,您可以包括chmod
命令,以确保文件以必要的限制权限创建,以使您的 ACL 按预期工作。
为了演示,让我们创建new_perm_dir
目录,并在其中设置继承的 ACL。我希望我的 shell 脚本在此目录中创建的文件具有读/写访问权限,并且 Frank 只能具有读取权限。我不希望其他人能够读取这些文件:
[donnie@localhost ~]$ setfacl -m d:u:frank:r new_perm_dir
[donnie@localhost ~]$ ls -ld new_perm_dir
drwxrwxr-x+ 2 donnie donnie 26 Nov 12 13:16 new_perm_dir
[donnie@localhost ~]$ getfacl new_perm_dir
# file: new_perm_dir
# owner: donnie
# group: donnie
user::rwx
group::rwx
other::r-x
default:user::rwx
default:user:frank:r--
default:group::rwx
default:mask::rwx
default:other::r-x
[donnie@localhost ~]$
我只需要做的就是在u:frank
之前添加d:
,使其成为继承的 ACL。我保留了目录上的默认权限设置,允许每个人对目录进行读取。接下来,我将创建donnie_script.sh
shell 脚本,该脚本将在该目录中创建一个文件,并且仅为新文件的用户设置读/写权限:
#!/bin/bash
cd new_perm_dir
touch new_file.txt
chmod 600 new_file.txt
exit
使脚本可执行后,我将运行它并查看结果:
[donnie@localhost ~]$ ./donnie_script.sh
[donnie@localhost ~]$ cd new_perm_dir
[donnie@localhost new_perm_dir]$ ls -l
total 0
-rw-------+ 1 donnie donnie 0 Nov 12 13:16 new_file.txt
[donnie@localhost new_perm_dir]$ getfacl new_file.txt
# file: new_file.txt
# owner: donnie
# group: donnie
user::rw-
user:frank:r-- #effective:---
group::rwx #effective:---
mask::---
other::---
[donnie@localhost new_perm_dir]$
所以,new_file.txt
以正确的权限设置创建,并且具有允许 Frank 读取的 ACL。(我知道这是一个非常简化的例子,但您明白我的意思。)
通过使用 ACL 掩码删除特定权限
您可以使用-x
选项从文件或目录中删除 ACL。让我们回到我之前创建的acl_demo.txt
文件,并删除 Maggie 的 ACL:
[donnie@localhost ~]$ setfacl -x u:maggie acl_demo.txt
[donnie@localhost ~]$ getfacl acl_demo.txt
# file: acl_demo.txt
# owner: donnie
# group: donnie
user::rw-
user:frank:rw-
group::---
mask::rw-
other::---
[donnie@localhost ~]$
所以,Maggie 的 ACL 消失了。但是,-x
选项会删除整个 ACL,即使这并不是您真正想要的。如果您有一个设置了多个权限的 ACL,您可能只想删除一个权限,而保留其他权限。在这里,我们看到 Frank 仍然有他的 ACL,允许他读/写访问。现在,假设我们想要删除写权限,同时仍然允许他读权限。为此,我们需要应用一个掩码:
[donnie@localhost ~]$ setfacl -m m::r acl_demo.txt
[donnie@localhost ~]$ ls -l acl_demo.txt
-rw-r-----+ 1 donnie donnie 0 Nov 9 14:37 acl_demo.txt
[donnie@localhost ~]$ getfacl acl_demo.txt
# file: acl_demo.txt
# owner: donnie
# group: donnie
user::rw-
user:frank:rw- #effective:r--
group::---
mask::r--
other::---
[donnie@localhost ~]$
m::r
在 ACL 上设置了只读掩码。运行getfacl
显示 Frank 仍然具有读/写 ACL,但旁边的注释显示他的有效权限是只读。因此,Frank 的文件写权限现在消失了。如果我们为其他用户设置了 ACL,这个掩码也会以相同的方式影响他们。
使用 tar --acls 选项来防止备份期间 ACLs 的丢失
如果您需要使用tar
来创建文件或目录的备份,并且这些文件或目录有 ACLs 分配给它,您需要包括--acls
选项开关。否则,ACLs 将会丢失。为了证明这一点,我将创建perm_demo_dir
目录的备份,没有使用--acls
选项。首先,请注意,我在此目录中的文件上有 ACLs,最后两个文件上的+
符号表示了这一点:
[donnie@localhost ~]$ cd perm_demo_dir
[donnie@localhost perm_demo_dir]$ ls -l
total 0
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file1.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file2.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file3.txt
-rw-rw-r--. 1 donnie accounting 0 Nov 5 20:17 file4.txt
-rw-rw----+ 1 donnie donnie 0 Nov 9 15:19 frank_file.txt
-rw-rw----+ 1 donnie donnie 0 Nov 12 12:29 new_file.txt
[donnie@localhost perm_demo_dir]$
现在,我将不使用--acls
进行备份:
[donnie@localhost perm_demo_dir]$ cd
[donnie@localhost ~]$ tar cJvf perm_demo_dir_backup.tar.xz perm_demo_dir/
perm_demo_dir/
perm_demo_dir/file1.txt
perm_demo_dir/file2.txt
perm_demo_dir/file3.txt
perm_demo_dir/file4.txt
perm_demo_dir/frank_file.txt
perm_demo_dir/new_file.txt
[donnie@localhost ~]$
看起来不错,对吧?啊,但外表可能是具有欺骗性的。看看当我删除目录,然后从备份中恢复它时会发生什么:
[donnie@localhost ~]$ rm -rf perm_demo_dir/
[donnie@localhost ~]$ tar xJvf perm_demo_dir_backup.tar.xz
perm_demo_dir/
perm_demo_dir/file1.txt
perm_demo_dir/file2.txt
perm_demo_dir/file3.txt
perm_demo_dir/file4.txt
perm_demo_dir/frank_file.txt
perm_demo_dir/new_file.txt
[donnie@localhost ~]$ ls -l
total 812
. . .
drwxrwxr-x+ 2 donnie donnie 26 Nov 12 13:16 new_perm_dir
drwxrwx---. 2 donnie donnie 116 Nov 12 12:29 perm_demo_dir
-rw-rw-r--. 1 donnie donnie 284 Nov 13 13:45 perm_demo_dir_backup.tar.xz
. . .
[donnie@localhost ~]$ cd perm_demo_dir/
[donnie@localhost perm_demo_dir]$ ls -l
total 0
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file1.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file2.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file3.txt
-rw-rw-r--. 1 donnie donnie 0 Nov 5 20:17 file4.txt
-rw-rw----. 1 donnie donnie 0 Nov 9 15:19 frank_file.txt
-rw-rw----. 1 donnie donnie 0 Nov 12 12:29 new_file.txt
[donnie@localhost perm_demo_dir]$
我甚至不需要使用getfacl
来查看perm_demo_dir
目录及其所有文件中的 ACL 已经消失,因为它们现在已经没有了+
符号。现在,让我们看看当我包括--acls
选项时会发生什么。首先,我将向您展示为此目录及其唯一文件设置了 ACL:
[donnie@localhost ~]$ ls -ld new_perm_dir
drwxrwxr-x+ 2 donnie donnie 26 Nov 13 14:01 new_perm_dir
[donnie@localhost ~]$ ls -l new_perm_dir
total 0
-rw-------+ 1 donnie donnie 0 Nov 13 14:01 new_file.txt
[donnie@localhost ~]$
现在,我将使用带有--acls
的 tar:
[donnie@localhost ~]$ tar cJvf new_perm_dir_backup.tar.xz new_perm_dir/ --acls
new_perm_dir/
new_perm_dir/new_file.txt
[donnie@localhost ~]$
现在我将删除new_perm_dir
目录,并从备份中恢复它。同样,我将使用--acls
选项:
[donnie@localhost ~]$ rm -rf new_perm_dir/
[donnie@localhost ~]$ tar xJvf new_perm_dir_backup.tar.xz --acls
new_perm_dir/
new_perm_dir/new_file.txt
[donnie@localhost ~]$ ls -ld new_perm_dir
drwxrwxr-x+ 2 donnie donnie 26 Nov 13 14:01 new_perm_dir
[donnie@localhost ~]$ ls -l new_perm_dir
total 0
-rw-------+ 1 donnie donnie 0 Nov 13 14:01 new_file.txt
[donnie@localhost ~]$
+
符号的存在表明 ACL 确实在备份和恢复过程中幸存下来了。这其中稍微棘手的部分是,你必须在备份和恢复时都使用--acls
。如果你在任一次中省略了选项,你将丢失你的 ACL。
创建用户组并向其中添加成员
到目前为止,我一直在自己的家目录中进行所有演示,只是为了展示基本概念。但最终的目标是向你展示如何利用这些知识做一些更实际的事情,比如在共享组目录中控制文件访问。第一步是创建一个用户组并向其中添加成员。
假设我们想为市场部门的成员创建一个marketing
组:
[donnie@localhost ~]$ sudo groupadd marketing
[sudo] password for donnie:
[donnie@localhost ~]$
现在让我们添加一些成员。你可以通过三种不同的方式来做到这一点:
-
在创建用户帐户时添加成员
-
使用
usermod
来添加已经有用户帐户的成员 -
编辑
/etc/group
文件
在创建用户帐户时添加成员
首先,我们可以在创建用户帐户时将成员添加到组中,使用useradd
的-G
选项。在 Red Hat 或 CentOS 上,命令看起来是这样的:
[donnie@localhost ~]$ sudo useradd -G marketing cleopatra
[sudo] password for donnie:
[donnie@localhost ~]$ groups cleopatra
cleopatra : cleopatra marketing
[donnie@localhost ~]$
在 Debian/Ubuntu 上,命令看起来是这样的:
donnie@ubuntu3:~$ sudo useradd -m -d /home/cleopatra -s /bin/bash -G marketing cleopatra
donnie@ubuntu3:~$ groups cleopatra
cleopatra : cleopatra marketing
donnie@ubuntu3:~$
当然,我还需要以正常方式为 Cleopatra 分配一个密码:
[donnie@localhost ~]$ sudo passwd cleopatra
使用 usermod 将现有用户添加到组
好消息是,在 Red Hat 或 CentOS 或 Debian/Ubuntu 上都是一样的:
[donnie@localhost ~]$ sudo usermod -a -G marketing maggie
[sudo] password for donnie:
[donnie@localhost ~]$ groups maggie
maggie : maggie marketing
[donnie@localhost ~]$
在这种情况下,-a
是不必要的,因为 Maggie 不是任何其他次要组的成员。但是,如果她已经属于另一个组,那么-a
将是必要的,以防止覆盖任何现有的组信息,从而将她从以前的组中删除。
这种方法在 Ubuntu 系统上特别方便,因为在创建加密的家目录时需要使用adduser
。(正如我们在前一章中看到的,adduser
不会给你在创建帐户时添加用户到组的机会。)
通过编辑/etc/group 文件将用户添加到组
这种最后的方法是一个好办法,可以加快将多个现有用户添加到组的过程。首先,只需在您喜欢的文本编辑器中打开/etc/group
文件,并查找定义要添加成员的组的行:
. . .
marketing:x:1005:cleopatra,maggie
. . .
所以,我已经将 Cleopatra 和 Maggie 添加到了这个组。让我们编辑一下,再添加几个成员:
. . .
marketing:x:1005:cleopatra,maggie,vicky,charlie
. . .
完成后,保存文件并退出编辑器。
对于每个成员的groups
命令将显示我们微小作弊的效果非常好:
[donnie@localhost etc]$ sudo vim group
[donnie@localhost etc]$ groups vicky
vicky : vicky marketing
[donnie@localhost etc]$ groups charlie
charlie : charlie marketing
[donnie@localhost etc]$
这种方法非常适用于需要同时向组中添加大量成员的情况。
创建共享目录
我们情节中的下一个行动涉及创建一个共享目录,所有我们市场部门的成员都可以使用。现在,这是另一个引起一些争议的领域。有些人喜欢将共享目录放在文件系统的根级目录,而其他人喜欢将共享目录放在/home
目录中。还有一些人甚至有其他偏好。但实际上,这是个人偏好和/或公司政策的问题。除此之外,你把它们放在哪里并不重要。为了简化事情,我将在文件系统的根级目录中创建目录:
[donnie@localhost ~]$ cd /
[donnie@localhost /]$ sudo mkdir marketing
[sudo] password for donnie:
[donnie@localhost /]$ ls -ld marketing
drwxr-xr-x. 2 root root 6 Nov 13 15:32 marketing
[donnie@localhost /]$
新目录属于 root 用户。它的权限设置为755
,允许每个人读取和执行访问,只允许 root 用户写入访问。我们真正想要的是只允许市场部门的成员访问这个目录。我们首先更改所有权和组关联,然后设置适当的权限:
[donnie@localhost /]$ sudo chown nobody:marketing marketing
[donnie@localhost /]$ sudo chmod 770 marketing
[donnie@localhost /]$ ls -ld marketing
drwxrwx---. 2 nobody marketing 6 Nov 13 15:32 marketing
[donnie@localhost /]$
在这种情况下,我们没有任何特定的用户想要拥有该目录,我们也不希望 root 用户拥有它。因此,将所有权分配给nobody
伪用户帐户为我们提供了一种处理的方式。然后,我将770
权限值分配给目录,这允许所有marketing
组成员读/写/执行访问,同时让其他人离开。现在,让我们让我们的一个组成员登录,看看她是否可以在这个目录中创建一个文件:
[donnie@localhost /]$ su - vicky
Password:
[vicky@localhost ~]$ cd /marketing
[vicky@localhost marketing]$ touch vicky_file.txt
[vicky@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 vicky vicky 0 Nov 13 15:41 vicky_file.txt
[vicky@localhost marketing]$
好的,它有效了,除了一个小问题。文件属于 Vicky,这是应该的。但是,它也与 Vicky 的个人组相关联。为了更好地控制这些共享文件的访问权限,我们需要它们与marketing
组相关联。
在共享目录上设置 SGID 位和粘滞位
我之前告诉过你,在文件上设置 SUID 或 SGID 权限,特别是在可执行文件上,这是一种安全风险。但是,在共享目录上设置 SGID 是完全安全且非常有用的。
目录上的 SGID 行为与文件上的 SGID 行为完全不同。在目录上,SGID 将导致任何人创建的文件都与目录关联的相同组相关联。因此,牢记 SGID 权限值为2000
,让我们在我们的marketing
目录上设置 SGID:
[donnie@localhost /]$ sudo chmod 2770 marketing
[sudo] password for donnie:
[donnie@localhost /]$ ls -ld marketing
drwxrws---. 2 nobody marketing 28 Nov 13 15:41 marketing
[donnie@localhost /]$
在组的可执行位置上的s
表示命令执行成功。现在让 Vicky 重新登录创建另一个文件:
[donnie@localhost /]$ su - vicky
Password:
Last login: Mon Nov 13 15:41:19 EST 2017 on pts/0
[vicky@localhost ~]$ cd /marketing
[vicky@localhost marketing]$ touch vicky_file_2.txt
[vicky@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 vicky marketing 0 Nov 13 15:57 vicky_file_2.txt
-rw-rw-r--. 1 vicky vicky 0 Nov 13 15:41 vicky_file.txt
[vicky@localhost marketing]$
Vicky 的第二个文件与marketing
组相关联,这正是我们想要的。只是为了好玩,让我们让 Charlie 做同样的事情:
[donnie@localhost /]$ su - charlie
Password:
[charlie@localhost ~]$ cd /marketing
[charlie@localhost marketing]$ touch charlie_file.txt
[charlie@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
-rw-rw-r--. 1 vicky marketing 0 Nov 13 15:57 vicky_file_2.txt
-rw-rw-r--. 1 vicky vicky 0 Nov 13 15:41 vicky_file.txt
[charlie@localhost marketing]$
再次,Charlie 的文件与marketing
组相关联。但是,由于没有人能理解的一些奇怪原因,Charlie 真的不喜欢 Vicky,并决定删除她的文件,纯粹是出于恶意:
[charlie@localhost marketing]$ rm vicky*
rm: remove write-protected regular empty file ‘vicky_file.txt’? y
[charlie@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
[charlie@localhost marketing]$
系统抱怨 Vicky 的原始文件受到写保护,因为它仍然与她的个人组相关联。但是,系统仍然允许 Charlie 删除它,即使没有 sudo 权限。而且,由于 Charlie 对第二个文件有写访问权限,因为它与marketing
组相关联,系统允许他毫不犹豫地删除它。
好的。所以,Vicky 抱怨了这个问题,并试图让 Charlie 被解雇。但是,我们勇敢的管理员有一个更好的主意。他将设置粘滞位,以防止这种情况再次发生。由于 SGID 位的值为2000
,粘滞位的值为1000
,我们可以将两者相加得到值为3000
:
[donnie@localhost /]$ sudo chmod 3770 marketing
[sudo] password for donnie:
[donnie@localhost /]$ ls -ld marketing
drwxrws--T. 2 nobody marketing 30 Nov 13 16:03 marketing
[donnie@localhost /]$
在其他人的可执行位置上的T
表示设置了粘滞位。由于T
是大写的,我们知道其他人的可执行权限没有被设置。设置了粘滞位将阻止组成员删除其他人的文件。让 Vicky 演示当她试图对 Charlie 进行报复时会发生什么:
[donnie@localhost /]$ su - vicky
Password:
Last login: Mon Nov 13 15:57:41 EST 2017 on pts/0
[vicky@localhost ~]$ cd /marketing
[vicky@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
[vicky@localhost marketing]$ rm charlie_file.txt
rm: cannot remove ‘charlie_file.txt’: Operation not permitted
[vicky@localhost marketing]$ rm -f charlie_file.txt
rm: cannot remove ‘charlie_file.txt’: Operation not permitted
[vicky@localhost marketing]$ ls -l
total 0
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
[vicky@localhost marketing]$
即使使用-f
选项,Vicky 仍然无法删除 Charlie 的文件。Vicky 在这个系统上没有sudo
权限,所以她尝试是没有用的。
使用 ACL 访问共享目录中的文件
目前,marketing
组的所有成员都可以读/写其他组成员的文件。将对文件的访问限制为仅特定组成员与我们已经讨论过的相同的两步过程。
设置权限并创建 ACL
首先,Vicky 设置了普通权限,只允许她访问她的文件。然后,她会设置 ACL:
[vicky@localhost marketing]$ echo "This file is only for my good friend, Cleopatra." > vicky_file.txt
[vicky@localhost marketing]$ chmod 600 vicky_file.txt
[vicky@localhost marketing]$ setfacl -m u:cleopatra:r vicky_file.txt
[vicky@localhost marketing]$ ls -l
total 4
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
-rw-r-----+ 1 vicky marketing 49 Nov 13 16:24 vicky_file.txt
[vicky@localhost marketing]$ getfacl vicky_file.txt
# file: vicky_file.txt
# owner: vicky
# group: marketing
user::rw-
user:cleopatra:r--
group::---
mask::r--
other::---
[vicky@localhost marketing]$
这里没有什么是你之前没有见过的。Vicky 只是从组和其他人那里删除了所有权限,并设置了一个 ACL,只允许 Cleopatra 读取文件。让我们看看 Cleopatra 是否真的能读取它:
[donnie@localhost /]$ su - cleopatra
Password:
[cleopatra@localhost ~]$ cd /marketing
[cleopatra@localhost marketing]$ ls -l
total 4
-rw-rw-r--. 1 charlie marketing 0 Nov 13 15:59 charlie_file.txt
-rw-r-----+ 1 vicky marketing 49 Nov 13 16:24 vicky_file.txt
[cleopatra@localhost marketing]$ cat vicky_file.txt
This file is only for my good friend, Cleopatra.
[cleopatra@localhost marketing]$
到目前为止,一切都很好。但是,Cleopatra 能写入吗?
[cleopatra@localhost marketing]$ echo "You are my friend too, Vicky." >> vicky_file.txt
-bash: vicky_file.txt: Permission denied
[cleopatra@localhost marketing]$
好的,Cleopatra 不能这样做,因为 Vicky 只允许她在 ACL 中拥有读权限。
Charlie 尝试使用为 Cleopatra 设置的 ACL 访问 Vicky 的文件
现在,不过,那个狡猾的 Charlie 呢,他想要窥探其他用户的文件呢?
[donnie@localhost /]$ su - charlie
Password:
Last login: Mon Nov 13 15:58:56 EST 2017 on pts/0
[charlie@localhost ~]$ cd /marketing
[charlie@localhost marketing]$ cat vicky_file.txt
cat: vicky_file.txt: Permission denied
[charlie@localhost marketing]$
所以,是的,只有 Cleopatra 才能访问 Vicky 的文件,即使是只读也是如此。
动手实验 - 创建共享组目录
在这个实验中,你将把本章学到的一切放在一起,为一个组创建一个共享目录。你可以在你的任一虚拟机上完成这个操作:
- 在任一虚拟机上创建
sales
组:
sudo groupadd sales
- 创建用户 Mimi、Mr. Gray 和 Mommy,并在创建账户时将他们添加到 sales 组中。
在 CentOS 虚拟机上执行:
sudo useradd -G sales mimi
sudo useradd -G sales mrgray
sudo useradd -G sales mommy
在 Ubuntu 虚拟机上执行:
sudo useradd -m -d /home/mimi -s /bin/bash -G sales mimi
sudo useradd -m -d /home/mrgray -s /bin/bash -G sales mrgray
sudo useradd -m -d /home/mommy -s /bin/bash -G sales mommy
-
为每个用户分配一个密码。
-
在文件系统的根目录级别创建
sales
目录。设置适当的所有权和权限,包括 SGID 和粘性位:
sudo mkdir /sales
sudo chown nobody:sales /sales
sudo chmod 3770 /sales
ls -ld /sales
- 以 Mimi 的身份登录,并让她创建一个文件:
su - mimi
cd /sales
echo "This file belongs to Mimi." > mimi_file.txt
ls -l
- 让 Mimi 在她的文件上设置 ACL,只允许 Mr. Gray 读取。然后,让 Mimi 退出登录:
chmod 600 mimi_file.txt
setfacl -m u:mrgray:r mimi_file.txt
getfacl mimi_file.txt
ls -l
exit
- 让 Mr. Gray 登录,看看他能否对 Mimi 的文件做些什么。然后,让 Mr. Gray 创建自己的文件并退出登录:
su - mrgray
cd /sales
cat mimi_file.txt
echo "I want to add something to this file." >>
mimi_file.txt
echo "Mr. Gray will now create his own file." >
mr_gray_file.txt
ls -l
exit
- Mommy 现在将登录并尝试通过窥探其他用户的文件和尝试删除它们来制造混乱:
su - mommy
cat mimi_file.txt
cat mr_gray_file.txt
rm -f mimi_file.txt
rm -f mr_gray_file.txt
exit
- 实验结束。
总结
在本章中,我们看到了如何将自主访问控制提升到更高的水平。我们首先看到了如何创建和管理访问控制列表,以提供对文件和目录的更精细的访问控制。然后,我们看到了如何为特定目的创建用户组,以及如何向其中添加成员。然后,我们看到了如何使用 SGID 位、粘性位和访问控制列表来管理共享组目录。
但有时,自主访问控制可能不足以完成工作。对于这些时候,我们还有强制访问控制,我们将在下一章中介绍。到时候再见。
第七章:使用 SELinux 和 AppArmor 实施强制访问控制
在前几章中,我们看到,自主访问控制允许用户控制谁可以访问他们自己的文件和目录。但是,如果您的公司需要对谁访问什么拥有更多的管理控制权呢?为此,我们需要某种强制访问控制或 MAC。
我知道解释 DAC 和 MAC 之间的区别的最好方法是回想起我在海军时的日子。那时我在潜艇上工作,我必须有最高机密级别的许可才能做我的工作。使用 DAC,我有能力将我的最高机密级别的书带到餐厅,交给一个没有那个级别许可的厨师。使用 MAC,有规定阻止我这样做。在操作系统上,事情基本上是一样的。
Linux 有几种不同的 MAC 系统可用。本章将涵盖的两种是 SELinux 和 AppArmor。
在本章中,我们将涵盖以下主题:
-
SELinux 是什么以及它如何有益于系统管理员
-
如何为文件和目录设置安全上下文
-
如何使用 setroubleshoot 来排除 SELinux 问题
-
查看 SELinux 策略以及如何创建自定义策略
-
AppArmor 是什么以及它如何有益于系统管理员
-
查看 AppArmor 策略
-
使用 AppArmor 命令行实用程序
-
排除 AppArmor 问题
SELinux 如何有益于系统管理员
SELinux 是由美国国家安全局开发的免费开源软件项目。虽然理论上它可以安装在任何 Linux 发行版上,但只有红帽类型的发行版才预先设置并启用了它。它使用 Linux 内核模块中的代码,以及文件系统扩展属性,以帮助确保只有经过授权的用户和进程才能访问敏感文件或系统资源。SELinux 有三种使用方式:
-
它可以帮助防止入侵者利用系统
-
它可以用来确保只有具有适当安全许可的用户才能访问标有安全分类的文件
-
除了 MAC,SELinux 还可以用作一种基于角色的访问控制
在本章中,我只会涵盖这三种用法中的第一种,因为这是 SELinux 最常用的方式。还有一个事实,涵盖这三种用法将需要写一整本书,而我在这里没有空间来做。
如果您阅读完这篇关于 SELinux 的介绍,发现您仍然需要更多关于 SELinux 的信息,您可以在 Packt Publishing 网站上找到关于这个主题的整本书和课程。
那么 SELinux 如何有益于繁忙的系统管理员呢?嗯,也许你还记得几年前,有关Shellshock漏洞的新闻震惊了世界。基本上,Shellshock 是 Bash shell 中的一个漏洞,允许入侵者通过获取 root 权限来入侵系统并利用它。对于运行 SELinux 的系统,入侵者仍然有可能入侵,但 SELinux 将阻止他们成功运行其利用程序。
SELinux 还是另一种可以帮助保护用户家目录中数据的机制。如果您有一台设置为网络文件系统服务器、Samba 服务器或 Web 服务器的机器,除非您明确配置 SELinux 允许该行为,否则 SELinux 将阻止这些守护程序访问用户的家目录。
在 Web 服务器上,您可以使用 SELinux 防止恶意 CGI 脚本或 PHP 脚本的执行。如果您的服务器不需要运行 CGI 或 PHP 脚本,您可以在 SELinux 中禁用它们。
在旧版本的 Docker 中,没有强制访问控制,普通用户很容易就能打破 Docker 容器并获得对主机的 root 级访问权限。尽管 Docker 的安全性已经得到改善,但 SELinux 仍然是加固运行 Docker 容器的服务器的有用工具。
现在,你可能认为每个人都会使用这样一个伟大的工具,对吗?遗憾的是,情况并非如此。在开始阶段,SELinux 因为难以使用而声名狼藉,许多管理员会选择禁用它。事实上,你在网上或 YouTube 上看到的很多教程都把禁用 SELinux作为第一步。在本节中,我想向你展示事情已经改善,SELinux 不再应该有坏名声。
为文件和目录设置安全上下文
把 SELinux 想象成一个被吹捧的标签系统。它通过扩展文件属性向文件和目录添加标签,称为安全上下文。它还向系统进程添加相同类型的标签,称为域。要在你的 CentOS 机器上查看这些上下文和域,可以使用ls
或ps
的-Z
选项。例如,我的家目录中的文件和目录如下所示:
[donnie@localhost ~]$ ls -Z
drwxrwxr-x. donnie donnie unconfined_u:object_r:user_home_t:s0 acl_demo_dir
-rw-rw-r--. donnie donnie unconfined_u:object_r:user_home_t:s0 yum_list.txt
[donnie@localhost ~]$
我的系统上的进程看起来像这样:
[donnie@localhost ~]$ ps -Z
LABEL PID TTY TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 1322 pts/0 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3978 pts/0 00:00:00 ps
[donnie@localhost ~]$
现在,让我们来分解一下。在ls -Z
和ps -Z
命令的输出中,我们有以下部分:
-
SELinux 用户:在这两种情况下,SELinux 用户是通用的
unconfined_u
-
SELinux 角色:在
ls -Z
示例中,我们看到角色是object_r
,在ps -Z
示例中是unconfined_r
-
类型:在
ls -Z
输出中是user_home_t
,在ps -Z
输出中是unconfined_t
-
敏感度:在
ps -Z
输出中是s0
。在ps -Z
输出中是s0-s0
-
类别:在
ls -Z
输出中我们看不到类别,但在ps -Z
输出中我们看到c0.c1023
在所有先前的安全上下文和安全域组件中,我们现在只关心类型。在本章中,我们只关心一个正常的 Linux 管理员需要了解的内容,以防止入侵者利用系统,而类型是我们需要使用的这些组件中的唯一一个。当我们设置高级的基于安全分类的访问控制和基于角色的访问控制时,所有其他组件都会发挥作用。
好的,这里是一个有些过于简化的解释,说明这如何帮助 Linux 管理员维护安全性。我们希望系统进程只能访问我们允许它们访问的对象。(系统进程包括诸如 Web 服务器守护程序、FTP 守护程序、Samba 守护程序和安全 Shell 守护程序等。对象包括文件、目录和网络端口等。)为了实现这一点,我们将为所有的进程和对象分配一个类型。然后我们将创建策略,定义哪些进程类型可以访问哪些对象类型。
幸运的是,当你安装任何红帽类型的发行版时,几乎所有的艰苦工作都已经为你完成。红帽类型的发行版都已经默认启用了 SELinux,并设置了针对的策略。把这个针对的策略想象成一个相对宽松的策略,允许普通桌面用户坐在电脑前进行业务操作,而不需要调整任何 SELinux 设置。但是,如果你是服务器管理员,你可能会发现自己需要调整这个策略,以允许服务器守护程序执行你需要它们执行的操作。
针对的策略,默认安装的策略是正常的 Linux 管理员在日常工作中会使用的。如果你查看你的 CentOS 虚拟机的存储库,你会发现还有其他几个,这些我们在本书中不会涉及。
安装 SELinux 工具
由于某种我永远无法理解的怪异原因,默认情况下不会安装您需要管理 SELinux 的工具,即使 SELinux 本身已经安装。因此,在您的 CentOS 虚拟机上,您需要做的第一件事是安装它们:
sudo yum install setools policycoreutils policycoreutils-python
在本章的后面部分,我们将看看如何使用 setroubleshoot 来帮助诊断 SELinux 问题。为了在那里查看一些很酷的错误消息,现在就安装 setroubleshoot,并通过重新启动auditd
守护程序来激活它。(没有 setroubleshoot 守护程序,因为 setroubleshoot 是由auditd
守护程序控制的。)我们有以下代码:
sudo yum install setroubleshoot
sudo service auditd restart
我们必须处理的一个小 systemd 怪癖是,当使用 systemd 守护程序时,你不能用正常的systemctl
命令停止或重新启动auditd
守护程序。然而,老式的service
命令可以工作。(不,我不知道为什么。)
根据您在安装 CentOS 时选择的安装类型,您可能已经安装了 setroubleshoot,也可能没有。为了确保,继续运行命令来安装它。如果 setroubleshoot 已经存在,运行这个命令不会有任何问题。
现在你有了开始的所需。
在启用 SELinux 的情况下创建 Web 内容文件
现在,让我们看看如果您的 Web 内容文件设置了错误的 SELinux 类型会发生什么。首先,我们将在我们的 CentOS 虚拟机上安装、启用和启动 Apache Web 服务器。(请注意,包括--now
选项允许我们在一个步骤中启用和启动守护程序。)我们有以下代码:
sudo yum install httpd
sudo systemctl enable --now httpd
如果您还没有这样做,您将希望配置防火墙以允许访问 Web 服务器:
[donnie@localhost ~]$ sudo firewall-cmd --permanent --add-service=http
success
[donnie@localhost ~]$ sudo firewall-cmd --reload
success
[donnie@localhost ~]$
当我们查看 Apache 进程的 SELinux 信息时,我们会看到这个:
[donnie@localhost ~]$ ps ax -Z | grep httpd
system_u:system_r:httpd_t:s0 3689 ? Ss 0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0 3690 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0 3691 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0 3692 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0 3693 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0 3694 ? S 0:00 /usr/sbin/httpd -DFOREGROUND
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3705 pts/0 R+ 0:00 grep --color=auto httpd
[donnie@localhost ~]$
就像我之前说的,我们对用户或角色不感兴趣。但是,我们对类型感兴趣,在这种情况下是httpd_t
。
在红帽类型的系统上,我们通常会将 Web 内容文件放在/var/www/html
目录中。让我们看看html
目录的 SELinux 上下文:
[donnie@localhost www]$ pwd
/var/www
[donnie@localhost www]$ ls -Zd html/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html/
[donnie@localhost www]$
类型是httpd_sys_content
,所以httpd
守护程序应该能够访问这个目录。目前它是空的,所以让我们cd
进入它并创建一个简单的索引文件:
[donnie@localhost www]$ cd html
[donnie@localhost html]$ pwd
/var/www/html
[donnie@localhost html]$ sudo vim index.html
我会把这个放到文件中,如下所示:
<html>
<head>
<title>
Test of SELinux
</title>
</head>
<body>
Let's see if this SELinux stuff really works!
</body>
</html>
好吧,就像我说的,这很简单,因为我的 HTML 手工编码技能已经不如以前了。但是,它仍然满足我们当前的目的。
查看 SELinux 上下文时,我们看到文件具有与html
目录相同的类型:
[donnie@localhost html]$ ls -Z
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
[donnie@localhost html]$
现在我可以从我信任的 OpenSUSE 工作站的网络浏览器导航到这个页面:
现在,让我们看看如果我决定在自己的家目录中创建内容文件,然后将它们移动到html
目录中会发生什么。首先,让我们看看我的新文件的 SELinux 上下文是什么:
[donnie@localhost ~]$ pwd
/home/donnie
[donnie@localhost ~]$ ls -Z index.html
-rw-rw-r--. donnie donnie unconfined_u:object_r:user_home_t:s0 index.html
[donnie@localhost ~]$
上下文类型现在是user_home_t
,这是一个确切的指示,表明我是在我的家目录中创建的。我现在将文件移动到html
目录,覆盖旧文件:
[donnie@localhost ~]$ sudo mv index.html /var/www/html/
[sudo] password for donnie:
[donnie@localhost ~]$ cd /var/www/html
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:user_home_t:s0 index.html
[donnie@localhost html]$
即使我把文件移动到/var/www/html
目录,SELinux 类型仍然与用户的家目录相关联。现在,我将转到我的主机机器的浏览器上刷新页面:
所以,我有一个小问题。分配给我的文件的类型与 httpd 守护程序进程的类型不匹配,因此 SELinux 不允许httpd
进程访问该文件。
如果我将文件复制到html
目录而不是移动它,SELinux 上下文将会改变以匹配目标目录的上下文。
修复不正确的 SELinux 上下文
好吧,所以我有这个没有人可以访问的 Web 内容文件,我真的不想创建一个新的。那我该怎么办呢?实际上,我们有三种不同的实用程序来解决这个问题:
-
chcon
-
restorecon
-
semanage
使用 chcon
有两种方法可以使用chcon
来修复文件或目录上的不正确的 SELinux 类型。第一种方法是手动指定正确的类型:
[donnie@localhost html]$ sudo chcon -t httpd_sys_content_t index.html
[sudo] password for donnie:
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:httpd_sys_content_t:s0 index.html
[donnie@localhost html]$
我们可以使用chcon
来更改上下文的任何部分,但正如我一直在说的,我们只对类型感兴趣,这可以通过-t
选项进行更改。您可以在ls -Z
输出中看到命令成功执行了。
使用chcon
的另一种方法是引用具有正确上下文的文件。出于演示目的,我将index.html
文件更改回了主目录类型,并在/var/www/html
目录中创建了一个新文件:
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:user_home_t:s0 index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 some_file.html
[donnie@localhost html]$
正如您所看到的,我在此目录中创建的任何文件都将自动具有正确的 SELinux 上下文设置。现在,让我们使用该新文件作为参考,以便在index.html
文件上设置正确的上下文:
[donnie@localhost html]$ sudo chcon --reference some_file.html index.html
[sudo] password for donnie:
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:httpd_sys_content_t:s0 index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 some_file.html
[donnie@localhost html]$
因此,我使用了--reference
选项,并指定了要用作参考的文件。要更改的文件列在命令的末尾。
现在,这一切都很好,但我想找到一种更简单的方法,不需要输入那么多。毕竟,我是个老人,不想过度劳累自己。因此,让我们来看看restorecon
实用程序。
使用 restorecon
使用restorecon
很容易。只需输入restorecon
,然后输入需要更改的文件的名称。再次,我将index.html
文件的上下文更改回了主目录类型。不过这次,我使用restorecon
来设置正确的类型:
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:user_home_t:s0 index.html
[donnie@localhost html]$ sudo restorecon index.html
[donnie@localhost html]$ ls -Z
-rw-rw-r--. donnie donnie unconfined_u:object_r:httpd_sys_content_t:s0 index.html
[donnie@localhost html]$
就是这样。
您还可以使用chcon
和restorecon
来更改整个目录及其内容的上下文。对于任何一个,只需使用-R
选项。例如:
sudo chcon -R -t httpd_sys_content_t /var/www/html/
sudo restorecon -R /var/www/html/
(记住:-R
代表递归。)
尽管这并不会影响我们访问此文件的能力,但仍然有最后一件事要处理。也就是说,我需要将文件的所有权更改为 Apache 用户:
[donnie@localhost html]$ sudo chown apache: index.html
[sudo] password for donnie:
[donnie@localhost html]$ ls -l
total 4
-rw-rw-r--. 1 apache apache 125 Nov 22 16:14 index.html
[donnie@localhost html]$
使用 semanage
在我刚刚提到的情况下,无论是chcon
还是restorecon
都可以满足您的需求。活动的 SELinux 策略规定了某些目录中的安全上下文应该是什么样子。只要您在活动的 SELinux 策略中定义的目录中使用chcon
或restorecon
,就没问题。但是假设您在其他地方创建了一个目录,想要用来提供网页内容文件。您需要在该目录及其中的所有文件上设置httpd_sys_content_t
类型。但是,如果您使用chcon
或restorecon
进行操作,更改将无法在系统重新启动后保留。要使更改永久生效,您需要使用semanage
。
出于某种奇怪的原因,假设我想要从/home
目录中创建的目录中提供网页内容:
[donnie@localhost home]$ pwd
/home
[donnie@localhost home]$ sudo mkdir webdir
[sudo] password for donnie:
[donnie@localhost home]$ ls -Zd webdir
drwxr-xr-x. root root unconfined_u:object_r:home_root_t:s0 webdir
[donnie@localhost home]$
因为我不得不使用我的 sudo 权限在这里创建目录,它与 root 用户的home_root_t
类型相关联,而不是正常的user_home_dir_t
类型。我在此目录中创建的任何文件都将具有相同的类型:
[donnie@localhost webdir]$ ls -Z
-rw-r--r--. root root unconfined_u:object_r:home_root_t:s0 index.html
[donnie@localhost webdir]$
下一步是使用semanage
将此目录和httpd_sys_content_t
类型的永久映射添加到活动策略的上下文列表中:
[donnie@localhost home]$ sudo semanage fcontext -a -t httpd_sys_content_t "/home/webdir(/.*)?"
[donnie@localhost home]$ ls -Zd /home/webdir
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /home/web_dir
[donnie@localhost home]$
好的,这是semanage
命令的详细说明:
-
fcontext
:因为semanage
有许多用途,我们必须指定我们要处理文件上下文。 -
-a
:这指定我们要为活动的 SELinux 策略的上下文列表添加新记录。 -
-t
:这指定了我们要映射到新目录的类型。在这种情况下,我们正在使用httpd_sys_content
类型创建新映射。 -
/home/webdir(/.*)?
:这一堆胡言乱语就是所谓的正则表达式。我不能在这里详细介绍正则表达式的细节,所以简单地说正则表达式是一种我们用来匹配文本模式的语言。(是的,我故意说是而不是are,因为正则表达式是整体语言的名称。)在这种情况下,我必须使用这个特定的正则表达式来使这个semanage
命令递归,因为semanage
没有-R
选项开关。通过这个正则表达式,我是在说我希望在这个目录中创建的任何东西都具有与目录本身相同的 SELinux 类型。
最后一步是对该目录执行restorecon -R
,以确保已设置正确的标签:
[donnie@localhost home]$ sudo restorecon -R webdir
[donnie@localhost home]$ ls -Zd /home/webdir
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /home/webdir
[donnie@localhost home]$
是的,我知道。你正在看着这个说,“但是,这个'ls -Zd'输出看起来和你执行 semanage 命令之后一样。”而且,你是对的。在运行semanage
命令之后,类型似乎已经正确设置。但是semanage-fcontext
手册上说无论如何都要运行restorecon
,所以我就这么做了。
有关如何使用semanage
管理安全上下文的更多信息,请参阅手册页,输入man semanage-fcontext
。
实践实验室 - SELinux 类型强制执行
在这个实验室中,你将安装 Apache web 服务器和适当的 SELinux 工具。然后,你将查看将错误的 SELinux 类型分配给 web 内容文件的影响。
- 安装 Apache,以及所有必需的 SELinux 工具:
sudo yum install httpd setroubleshoot setools
policycoreutils policycoreutils-python
- 通过重新启动
auditd
服务来激活 setroubleshoot:
sudo service auditd restart
- 启用并启动 Apache 服务,并在防火墙上打开端口
80
:
sudo systemctl enable --now httpd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
- 在
/var/www/html
目录中,创建一个带有以下内容的index.html
文件:
<html>
<head>
<title>SELinux Test Page</title>
</head>
<body>
This is a test of SELinux.
</body>
</html>
- 查看
index.html
文件的 SELinux 信息:
ls -Z index.html
-
在主机机器的 web 浏览器中,导航到 CentOS 虚拟机的 IP 地址。你应该能够查看页面。
-
通过将
index.html
文件的类型更改为不正确的内容来引发 SELinux 违规:
sudo chcon -t tmp_t index.html
ls -Z index.html
-
返回到主机的 web 浏览器,重新加载文档。现在你应该看到一个 Forbidden 消息。
-
使用
restorecon
将文件更改回正确的类型:
sudo restorecon index.html
- 在主机机器的 web 浏览器中重新加载页面。现在你应该能够查看页面了。
使用 setroubleshoot 进行故障排除
所以,你现在正在挠头说,“当我无法访问我应该能够访问的东西时,我怎么知道这是一个 SELinux 问题呢?”啊,我很高兴你问到了。
查看 setroubleshoot 消息
每当发生违反 SELinux 规则的事件时,它都会被记录在/var/log/audit/audit.log
文件中。有工具可以让你直接读取该日志,但是为了诊断 SELinux 问题,最好使用 setroubleshoot。setroubleshoot 的美妙之处在于它将audit.log
文件中晦涩难懂、难以解释的 SELinux 消息翻译成通俗易懂的语言。它发送到/var/log/messages
文件的消息甚至包含了如何解决问题的建议。为了展示这是如何工作的,让我们回到我们的问题,即/var/www/html
目录中的文件被分配了错误的 SELinux 类型。当然,我们立刻就知道问题所在,因为那个目录中只有一个文件,简单的ls -Z
就显示了它的问题。然而,暂且不管这个问题,假设我们不知道问题所在。通过在less
中打开/var/log/messages
文件并搜索sealert
,我们会找到这条消息:
Nov 26 21:30:21 localhost python: SELinux is preventing httpd from open access on the file /var/www/html/index.html.#012#012***** Plugin restorecon (92.2 confidence) suggests ************************#012#012If you want to fix the label. #012/var/www/html/index.html default label should be httpd_sys_content_t.#012Then you can run restorecon.#012Do#012# /sbin/restorecon -v /var/www/html/index.html#012#012***** Plugin catchall_boolean (7.83 confidence) suggests ******************#012#012If you want to allow httpd to read user content#012Then you must tell SELinux about this by enabling the 'httpd_read_user_content' boolean.#012#012Do#012setsebool -P httpd_read_user_content 1#012#012***** Plugin catchall (1.41 confidence) suggests **************************#012#012If you believe that httpd should be allowed open access on the index.html file by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'httpd' --raw | audit2allow -M my-httpd#012# semodule -i my-httpd.pp#012
这条消息的第一行告诉我们问题所在。它说 SELinux 正在阻止我们访问/var/www/html/index.html
文件,因为它的类型设置错误。然后给了我们几个修复问题的建议,第一个是运行restorecon
命令,就像我已经告诉你怎么做了一样。
阅读这些 setroubleshoot 消息时要记住的一个好的经验法则是,消息中的第一个建议通常是可以解决问题的。
使用图形 setroubleshoot 实用程序
到目前为止,我只谈到了在文本模式服务器上使用 setroubleshoot。毕竟,很常见看到运行在文本模式下的 Linux 服务器,所以我们所有的 Linux 用户都必须成为文本模式的战士。但是在桌面系统或安装了桌面界面的服务器上,有一个图形实用程序,当 setroubleshoot 检测到问题时会自动提醒你:
点击那个警报图标,你会看到这个:
点击“故障排除”按钮,你将看到如何解决问题的建议列表:
通常情况下,这些 GUI 工具都很容易理解,所以你不应该在理解上遇到任何问题。
在宽容模式下进行故障排除
如果你遇到像我刚刚展示的这样简单的问题,那么你可能可以假设 setroubleshoot 消息中的第一个建议告诉你的是安全的。但是有时候会出现更复杂的情况,可能会有多个问题。在这种情况下,你需要使用宽容模式。
当你首次安装 Red Hat 或 CentOS 系统时,SELinux 处于强制模式,这是默认设置。这意味着 SELinux 实际上会阻止违反活动 SELinux 策略的操作。这也意味着,如果在尝试执行某个操作时出现多个 SELinux 问题,SELinux 将在第一次违规后停止该操作。当发生这种情况时,SELinux 甚至不会看到剩下的问题,并且它们不会出现在messages
日志文件中。如果你在强制模式下尝试解决这些类型的问题,你就像是追逐自己尾巴的狗一样。你会一直转圈,却一事无成。
在宽容模式下,SELinux 允许违反策略的操作发生,但会记录它们。切换到宽容模式并做一些引发你之前看到的问题的操作,被禁止的操作将发生,但 setroubleshoot 会在messages
文件中记录所有这些操作。这样,你就能更好地了解需要做什么来使事情正常运行。
首先,让我们使用getenforce
来验证我们当前的模式是什么:
[donnie@localhost ~]$ sudo getenforce
Enforcing
[donnie@localhost ~]$
现在,让我们临时将系统置于宽容模式:
[donnie@localhost ~]$ sudo setenforce 0
[donnie@localhost ~]$ sudo getenforce
Permissive
[donnie@localhost ~]$
当我说“临时”时,我的意思是这只会持续到系统重启。重启后,你将回到强制模式。另外,请注意,在setenforce
后的0
表示我正在设置宽容模式。在完成故障排除后返回强制模式,将0
替换为1
:
[donnie@localhost ~]$ sudo setenforce 1
[donnie@localhost ~]$ sudo getenforce
Enforcing
[donnie@localhost ~]$
我们现在又回到了强制模式。
有时候,你可能需要在系统重启后使宽容模式持久化。一个例子是,如果你需要处理一个长时间禁用 SELinux 的系统。在这种情况下,你不应该只是将 SELinux 设置为强制模式然后重启。如果你这样做,系统将需要很长时间才能正确创建使 SELinux 工作的文件和目录标签,而在完成之前系统可能会锁死。首先将系统置于宽容模式,可以避免系统锁死,尽管重新标记过程仍然需要很长时间才能完成。
要使宽容模式在系统重启后持久化,你需要编辑/etc/sysconfig
目录中的selinux
文件。默认情况下,它是这样的:
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
你在这里看到的两个重要信息是 SELinux 处于强制模式,并且正在使用目标策略。要切换到宽容模式,只需更改SELINUX=
行,并保存文件:
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=permissive
# SELINUXTYPE= can take one of three two values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
sestatus
实用程序向我们展示了关于 SELinux 正在发生的许多有趣信息:
[donnie@localhost ~]$ sudo sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: permissive
Policy MLS status: enabled
Policy deny_unknown status: allowed
Max kernel policy version: 28
[donnie@localhost ~]$
这里我们感兴趣的两个项目是当前模式和配置文件中的模式。通过将配置文件更改为宽松模式,我们并没有改变当前运行模式。所以,我们仍然处于强制模式。切换到宽松模式要么是在我重新启动这台机器之前,要么是通过发出sudo setenforce 0
命令手动切换。当然,你不希望永远保持在宽松模式。一旦你不再需要宽松模式,将配置文件改回强制模式,并执行sudo setenforce 1
来改变运行模式。
处理 SELinux 策略
到目前为止,我们只看到了当文件上设置了不正确的 SELinux 类型时会发生什么,以及如何设置正确的类型。我们可能会遇到的另一个问题是,我们需要允许一个被活动 SELinux 策略禁止的操作。
查看布尔值
布尔值是 SELinux 策略的一部分,每个布尔值代表一个二进制选择。在 SELinux 策略中,一个布尔值要么允许某事,要么禁止某事。要查看系统上的所有布尔值,请运行getsebool -a
命令。(这是一个很长的列表,所以我只会在这里显示部分输出。):
[donnie@localhost ~]$ getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
auditadm_exec_content --> on
. . .
. . .
xserver_object_manager --> off
zabbix_can_network --> off
zarafa_setrlimit --> off
zebra_write_config --> off
zoneminder_anon_write --> off
zoneminder_run_sudo --> off
[donnie@localhost ~]$
要查看多个布尔值,-a
开关是必需的。如果你碰巧知道你想要查看的布尔值的名称,可以不加-a
,直接列出布尔值。继续我们之前讨论的 Apache Web 服务器主题,让我们看看是否允许 Apache 访问用户的主目录中的文件:
[donnie@localhost html]$ getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
[donnie@localhost html]$
这个布尔值是off
,这意味着 Apache 服务器守护程序不被允许访问用户主目录中的任何内容。这是一个重要的保护,你真的不想改变它。相反,只需将 Web 内容文件放在其他地方,这样你就不必改变这个布尔值。
很可能,你很少想要查看整个列表,你可能也不知道你想要查看的具体布尔值的名称。相反,你可能想通过grep
筛选输出,以便只查看某些内容。例如,要查看影响 Web 服务器的所有布尔值,请按照以下步骤:
[donnie@localhost html]$ getsebool -a | grep 'http'
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> off
. . .
. . .
httpd_use_nfs --> off
httpd_use_openstack --> off
httpd_use_sasl --> off
httpd_verify_dns --> off
named_tcp_bind_http_port --> off
prosody_bind_http_port --> off
[donnie@localhost html]$
这也是一个相当长的列表,但向下滚动一段时间,你会找到你要找的布尔值。
配置布尔值
实际上,你可能永远不会有理由允许用户从他们的主目录中提供 Web 内容。更有可能的是,你会设置类似 Samba 服务器的东西,这将允许 Windows 机器上的用户使用他们的图形 Windows 资源管理器访问 Linux 服务器上的主目录。但是,如果你设置了 Samba 服务器并且没有对 SELinux 做任何操作,用户将抱怨他们在 Samba 服务器的主目录中看不到任何文件。因为你是积极主动的类型,你不想听到用户的抱怨,你肯定会配置 SELinux 以允许 Samba 守护程序访问用户的主目录。你可能不知道具体的布尔值名称,但你可以很容易地找到它,如下所示:
[donnie@localhost html]$ getsebool -a | grep 'home'
git_cgi_enable_homedirs --> off
git_system_enable_homedirs --> off
httpd_enable_homedirs --> off
mock_enable_homedirs --> off
mpd_enable_homedirs --> off
openvpn_enable_homedirs --> on
samba_create_home_dirs --> off
samba_enable_home_dirs --> off
sanlock_enable_home_dirs --> off
spamd_enable_home_dirs --> on
ssh_chroot_rw_homedirs --> off
tftp_home_dir --> off
use_ecryptfs_home_dirs --> off
use_fusefs_home_dirs --> off
use_nfs_home_dirs --> off
use_samba_home_dirs --> off
xdm_write_home --> off
[donnie@localhost html]$
好吧,你知道布尔值的名称可能有home
这个词,所以你筛选了这个词。在列表的中间位置,你会看到samba_enable_home_dirs --> off
。你需要将其更改为on
,以便让用户从他们的 Windows 机器访问他们的主目录:
[donnie@localhost html]$ sudo setsebool samba_enable_home_dirs on
[sudo] password for donnie:
[donnie@localhost html]$ getsebool samba_enable_home_dirs
samba_enable_home_dirs --> on
[donnie@localhost html]$
用户现在可以访问他们应该能够访问的主目录,但只有在系统重新启动之前。没有-P
选项,你用setsebool
做的任何更改都只是临时的。所以,让我们使用-P
使更改永久生效:
[donnie@localhost html]$ sudo setsebool -P samba_enable_home_dirs on
[donnie@localhost html]$ getsebool samba_enable_home_dirs
samba_enable_home_dirs --> on
[donnie@localhost html]$
恭喜,你刚刚对 SELinux 策略进行了第一次更改。
保护你的 Web 服务器
再次查看getsebool -a | grep 'http'
命令的输出,您会发现大多数与 httpd 相关的布尔值默认处于关闭状态,只有少数处于打开状态。在设置 Web 服务器时,有两个布尔值是您通常需要打开的。
如果您需要设置一个带有某种基于 PHP 的内容管理系统的网站,例如 Joomla 或 Wordpress,您可能需要打开httpd_unified
布尔值。如果关闭此布尔值,Apache Web 服务器将无法与 PHP 引擎的所有组件正确交互:
[donnie@localhost ~]$ getsebool httpd_unified
httpd_unified --> off
[donnie@localhost ~]$ sudo setsebool -P httpd_unified on
[sudo] password for donnie:
[donnie@localhost ~]$ getsebool httpd_unified
httpd_unified --> on
[donnie@localhost ~]$
你通常需要打开的另一个布尔值是httpd_can_sendmail
布尔值。如果您需要网站通过表单发送邮件,或者需要设置带有基于 Web 的前端的邮件服务器,那么您肯定需要将其设置为on
:
[donnie@localhost ~]$ getsebool httpd_can_sendmail
httpd_can_sendmail --> off
[donnie@localhost ~]$ sudo setsebool -P httpd_can_sendmail on
[donnie@localhost ~]$ getsebool httpd_can_sendmail
httpd_can_sendmail --> on
[donnie@localhost ~]$
另一方面,默认情况下有一些布尔值是打开的,您可能需要考虑是否真的需要打开它们。例如,允许在 Web 服务器上运行 CGI 脚本确实代表潜在的安全风险。如果入侵者以某种方式上传了恶意的 CGI 脚本到服务器并运行它,可能会造成很大的损害。然而,出于某种奇怪的原因,默认的 SELinux 策略允许运行 CGI 脚本。如果您绝对确定在您的服务器上托管网站的人永远不需要运行 CGI 脚本,您可能需要考虑关闭此布尔值:
[donnie@localhost ~]$ getsebool httpd_enable_cgi
httpd_enable_cgi --> on
[donnie@localhost ~]$ sudo setsebool -P httpd_enable_cgi off
[donnie@localhost ~]$ getsebool httpd_enable_cgi
httpd_enable_cgi --> off
[donnie@localhost ~]$
保护网络端口
在您的系统上运行的每个网络守护程序都有一个特定的网络端口或一组网络端口分配给它,它将在这些端口上监听。/etc/services
文件包含常见守护程序及其关联的网络端口列表,但它不能阻止某人配置守护程序监听某些非标准端口。因此,如果没有一些机制来阻止它,一些狡猾的入侵者可能会植入某种恶意软件,导致守护程序监听非标准端口,可能会监听来自其主机的命令。
SELinux 通过只允许守护程序监听某些端口来防止此类恶意活动。使用semanage
查看允许端口的列表:
[donnie@localhost ~]$ sudo semanage port -l
[sudo] password for donnie:
SELinux Port Type Proto Port Number
afs3_callback_port_t tcp 7001
afs3_callback_port_t udp 7001
afs_bos_port_t udp 7007
afs_fs_port_t tcp 2040
afs_fs_port_t udp 7000, 7005
afs_ka_port_t udp 7004
afs_pt_port_t tcp 7002
afs_pt_port_t udp 7002
afs_vl_port_t udp 7003
. . .
. . .
zebra_port_t tcp 2606, 2608-2609, 2600-2604
zebra_port_t udp 2606, 2608-2609, 2600-2604
zented_port_t tcp 1229
zented_port_t udp 1229
zookeeper_client_port_t tcp 2181
zookeeper_election_port_t tcp 3888
zookeeper_leader_port_t tcp 2888
zope_port_t tcp 8021
[donnie@localhost ~]$
这又是一个非常长的列表,所以我只显示部分输出。不过,让我们缩小范围。假设我只想查看 Apache Web 服务器可以监听的端口列表。为此,我将使用我的好朋友grep
:
[donnie@localhost ~]$ sudo semanage port -l | grep 'http'
[sudo] password for donnie:
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
[donnie@localhost ~]$
有几个http
项目,但我只对http_port_t
项目感兴趣,因为它会影响正常的 Web 服务器操作。我们在这里看到 SELinux 将允许 Apache 监听端口80
,81
,443
,488
,8008
,8009
,8443
和9000
。由于 Apache 服务器是您可能有合法理由添加非标准端口的最有可能的守护程序,让我们以此为例。
首先,让我们进入/etc/httpd/conf/httpd.conf
文件,并查看 Apache 当前正在监听的端口。搜索Listen
,您会看到以下行:
Listen 80
我在这台机器上没有安装 SSL 模块,但如果我安装了,我将在/etc/httpd/conf.d
目录中有一个ssl.conf
文件,其中包含以下行:
Listen 443
因此,对于正常的非加密网站连接,默认配置只有 Apache 监听端口80
。对于安全的加密网站连接,Apache 监听端口443
。现在,让我们进入httpd.conf
文件,并将Listen 80
更改为 SELinux 不允许的端口号。例如,端口82
:
Listen 82
保存文件后,我将重新启动 Apache 以读取新的配置:
[donnie@localhost ~]$ sudo systemctl restart httpd
Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details.
[donnie@localhost ~]$
是的,我有问题。我将查看/var/log/messages
文件,看看 setroubleshoot 是否给了我一些线索:
Nov 29 16:39:21 localhost python: SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 82.#012#012***** Plugin bind_ports (99.5 confidence) suggests ************************#012#012If you want to allow /usr/sbin/httpd to bind to network port 82#012Then you need to modify the port type.#012Do#012# semanage port -a -t PORT_TYPE -p tcp 82#012 where PORT_TYPE is one of the following: http_cache_port_t, http_port_t, jboss_management_port_t, jboss_messaging_port_t, ntop_port_t, puppet_port_t.#012#012***** Plugin catchall (1.49 confidence) suggests **************************#012#012If you believe that httpd should be allowed name_bind access on the port 82 tcp_socket by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'httpd' --raw | audit2allow -M my-httpd#012# semodule -i my-httpd.pp#012
SELinux 阻止httpd
绑定到端口82
的问题在消息的第一行中定义。我们看到的第一个修复建议是使用semanage
将端口添加到允许端口列表中。因此,让我们这样做,并查看 Apache 端口列表:
[donnie@localhost ~]$ sudo semanage port -a 82 -t http_port_t -p tcp
[donnie@localhost ~]$ sudo semanage port -l | grep 'http_port_t'
http_port_t tcp 82, 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
[donnie@localhost ~]$
在 setroubleshoot 消息中并不清楚,但您需要在port -a
之后指定要添加的端口号。-t http_port_t
指定要添加端口的类型,-p tcp
指定要使用 TCP 协议。
现在,真相即将揭晓。Apache 守护程序这次会启动吗?让我们看看:
[donnie@localhost ~]$ sudo systemctl restart httpd
[sudo] password for donnie:
[donnie@localhost ~]$ sudo systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2017-11-29 20:09:51 EST; 7s ago
Docs: man:httpd(8)
. . .
. . .
它起作用了,我们已经实现了酷炫。但是现在,我决定不再需要这个古怪的端口。删除它就像添加它一样容易:
[donnie@localhost ~]$ sudo semanage port -d 82 -t http_port_t -p tcp
[donnie@localhost ~]$ sudo semanage port -l | grep 'http_port_t'
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
[donnie@localhost ~]$
我所要做的就是用port -d
替换port -a
。当然,我还需要进入/etc/httpd/conf/httpd.conf
文件,将Listen 82
改回Listen 80
。
创建自定义策略模块
有时,您会遇到无法通过更改类型或设置布尔值来解决的问题。在这种情况下,您需要创建一个自定义策略模块,并使用audit2allow
实用程序来执行此操作。
这是几年前我遇到的一个问题的屏幕截图,当时我正在帮助客户在 CentOS 7 上设置 Postfix 邮件服务器:
因为某种我从未理解的奇怪原因,SELinux 不允许 Dovecot(邮件服务器的邮件传递代理组件)读取自己的dict
文件。没有布尔值可更改,也没有类型问题,因此 setroubleshoot 建议我创建一个自定义策略模块。这很容易做到,但您需要知道这在普通用户帐户上使用 sudo 不起作用。这是那些罕见时刻之一,您只需转到 root 用户命令提示符,并且还需要在 root 用户的主目录中:
sudo su -
在执行此操作之前,请确保将 SELinux 设置为宽松模式,然后执行某些操作以引发 SELinux 错误。这样,您就可以确保一个问题不会掩盖其他问题。
当您运行命令创建新的策略模块时,请确保用自己选择的自定义策略名称替换mypol
。在我的情况下,我将模块命名为dovecot_dict
,命令看起来是这样的:
grep dict /var/log/audit/audit.log | audit2allow -M dovecot_dict
我在这里做的是使用grep
搜索audit.log
文件中包含单词dict
的 SELinux 消息。然后我将该输出传输到audit2allow
,并使用-M
选项创建一个名为dovecot_dict
的自定义模块。
创建新的策略模块后,我将其插入 SELinux 策略中,如下所示:
semodule -i dovecot_dict.pp
还有第二个问题需要另一个自定义模块,但我只是重复了这个过程以生成另一个不同名称的模块。完成所有这些后,我重新加载了 SELinux 策略,以使我的新模块生效:
semodule -R
对于semodule
,-R
开关代表重新加载,而不是像大多数 Linux 命令那样递归。
完成所有这些后,我将 SELinux 重新设置为强制模式,并退出到自己的用户帐户。然后,我测试了设置以确保我已经解决了问题。
当然,您还要记住,您不希望每次在日志文件中看到sealert
消息时都修改 SELinux 策略或上下文。例如,考虑一下我设置主要用于运行 Docker 和 Docker 容器的 Oracle Linux 7 机器的messages
文件中的这段代码:
Jun 8 19:32:17 docker-1 setroubleshoot: SELinux is preventing /usr/bin/docker from getattr access on the file /etc/exports. For complete SELinux messages. run sealert -l b267929a-d3ad-45d5-806e-907449fc2739
Jun 8 19:32:17 docker-1 python: SELinux is preventing /usr/bin/docker from getattr access on the file /etc/exports.#012#012***** Plugin catchall (100\. confidence) suggests **************************#012#012If you believe that docker should be allowed getattr access on the exports file by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# grep docker /var/log/audit/audit.log | audit2allow -M mypol#012# semodule -i mypol.pp#012
Jun 8 19:32:17 docker-1 setroubleshoot: SELinux is preventing /usr/bin/docker from getattr access on the file /etc/shadow.rpmnew. For complete SELinux messages. run sealert -l bc566655-1fbc-4141-af48-ccd6c76a3d3b
Jun 8 19:32:17 docker-1 python: SELinux is preventing /usr/bin/docker from getattr access on the file /etc/shadow.rpmnew.#012#012***** Plugin catchall (100\. confidence) suggests **************************#012#012If you believe that docker should be allowed getattr access on the shadow.rpmnew file by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# grep docker /var/log/audit/audit.log | audit2allow -M mypol#012# semodule -i mypol.pp#012
这些消息是由早期版本的 Docker 尝试访问主机上的资源引起的。正如您所看到的,Docker 正在尝试访问一些相当敏感的文件,而 SELinux 正在阻止 Docker 这样做。对于早期版本的 Docker 而言,如果没有某种强制访问控制,普通的非特权用户很容易就能够从 Docker 容器中逃脱,并在主机系统上拥有 root 用户权限。当您看到这些消息时,您不希望自动告诉 SELinux 允许被禁止的操作。这可能是 SELinux 正在阻止某些真正糟糕的事情发生。
请确保在以下网址获取您的SELinux 着色书:opensource.com/business/13/11/selinux-policy-guide.
实践实验 - SELinux 布尔值和端口
在这个实验中,您将查看 Apache 尝试在未经授权的端口上监听的效果:
- 查看 SELinux 允许 Apache Web 服务器守护程序使用的端口:
sudo semanage port -l | grep 'http'
- 在您喜欢的文本编辑器中打开
/etc/httpd/conf/httpd.conf
文件。找到Listen 80
的那一行,并将其更改为Listen 82
。输入以下内容重新启动 Apache:
sudo systemctl restart httpd
- 输入以下内容查看您收到的错误消息:
sudo tail -20 /var/log/messages
- 将端口
82
添加到授权端口列表并重新启动 Apache:
sudo semanage port -a 82 -t http_port_t -p tcp
sudo semanage port -l
sudo systemctl restart httpd
- 删除您刚刚添加的端口:
sudo semanage -d 82 -t http_port_t -p tcp
- 返回
/etc/httpd/conf/httpd.conf
文件,并将Listen 82
改回Listen 80
。重新启动 Apache 守护程序以恢复正常操作。
AppArmor 如何有益于系统管理员
AppArmor 是与 SUSE 和 Ubuntu Linux 系列一起安装的强制访问控制系统。尽管它的设计几乎与 SELinux 完成相同的工作,但其操作模式有很大的不同:
-
SELinux 为所有系统进程和文件、目录或网络端口等所有对象打上标签。对于文件和目录,SELinux 将标签存储在它们各自的 inode 中作为扩展属性。(inode 是包含有关文件的所有信息的基本文件系统组件,除了文件名。)
-
AppArmor 使用路径名强制执行,这意味着您要指定要 AppArmor 控制的可执行文件的路径。这样,就不需要将标签插入文件或目录的扩展属性中。
-
使用 SELinux,您可以立即获得系统范围的保护。
-
使用 AppArmor,您可以为每个单独的应用程序创建一个配置文件。
-
无论是 SELinux 还是 AppArmor,您可能会偶尔发现自己不得不从头开始创建自定义策略模块,特别是如果您正在处理第三方应用程序或自制软件。使用 AppArmor 会更容易,因为编写 AppArmor 配置文件的语法比编写 SELinux 策略的语法要简单得多。而且,AppArmor 配备了可以帮助您自动化该过程的实用程序。
-
就像 SELinux 一样,AppArmor 可以帮助防止恶意行为者破坏您的一天,并保护用户数据。
因此,您可以看到 SELinux 和 AppArmor 都有优点和缺点,许多 Linux 管理员对自己更喜欢的那个有着强烈的感受。(为了避免被卷入争论,我将不表达自己的偏好。)另外,请注意,即使我们正在使用 Ubuntu 虚拟机,我在这里提供的信息,除了特定于 Ubuntu 的软件包安装命令之外,也适用于 SUSE Linux 发行版。
查看 AppArmor 配置文件
在/etc/apparmor.d
目录中,您将看到系统的 AppArmor 配置文件。(SELinux 的人说策略,但 AppArmor 的人说配置文件。)
donnie@ubuntu3:/etc/apparmor.d$ ls -l
total 72
drwxr-xr-x 5 root root 4096 Oct 29 15:21 abstractions
drwxr-xr-x 2 root root 4096 Nov 15 09:34 cache
drwxr-xr-x 2 root root 4096 Oct 29 14:43 disable
drwxr-xr-x 2 root root 4096 Apr 5 2016 force-complain
drwxr-xr-x 2 root root 4096 Oct 29 15:21 local
drwxr-xr-x 2 root root 4096 Oct 29 15:02 lxc
-rw-r--r-- 1 root root 198 Jun 14 16:15 lxc-containers
-rw-r--r-- 1 root root 3310 Apr 12 2016 sbin.dhclient
drwxr-xr-x 5 root root 4096 Oct 29 15:21 tunables
-rw-r--r-- 1 root root 125 Jun 14 16:15 usr.bin.lxc-start
-rw-r--r-- 1 root root 281 May 23 2017 usr.lib.lxd.lxd-bridge-proxy
-rw-r--r-- 1 root root 17667 Oct 18 05:04 usr.lib.snapd.snap-confine.real
-rw-r--r-- 1 root root 1527 Jan 5 2016 usr.sbin.rsyslogd
-rw-r--r-- 1 root root 1469 Sep 8 15:27 usr.sbin.tcpdump
donnie@ubuntu3:/etc/apparmor.d$
sbin.dhclient
文件和usr.*
文件都是 AppArmor 配置文件。您还会在lxc
和lxc-containers
子目录中找到其他一些配置文件。不过,在应用程序配置文件方面,这里并没有太多内容。
由于某种原因,OpenSUSE 的默认安装比 Ubuntu Server 安装了更多的配置文件。要在 Ubuntu 上安装更多配置文件,请使用以下命令:
sudo apt install apparmor-profiles apparmor-profiles-extra
在abstractions
子目录中,您会找到一些不完整的配置文件,但可以包含在完整的配置文件中。任何一个这些抽象文件都可以包含在任意数量的配置文件中。这样,您就不必每次创建配置文件时都重复编写相同的代码。只需包含一个抽象文件即可。
如果您熟悉编程概念,只需将抽象文件视为另一种包含文件。
以下是抽象文件的部分清单:
donnie@ubuntu3:/etc/apparmor.d/abstractions$ ls -l
total 320
-rw-r--r-- 1 root root 695 Mar 15 2017 apache2-common
drwxr-xr-x 2 root root 4096 Oct 29 15:21 apparmor_api
-rw-r--r-- 1 root root 308 Mar 15 2017 aspell
-rw-r--r-- 1 root root 1582 Mar 15 2017 audio
-rw-r--r-- 1 root root 1544 Mar 15 2017 authentication
-rw-r--r-- 1 root root 6099 Mar 15 2017 base
-rw-r--r-- 1 root root 1512 Mar 15 2017 bash
-rw-r--r-- 1 root root 798 Mar 15 2017 consoles
-rw-r--r-- 1 root root 714 Mar 15 2017 cups-client
-rw-r--r-- 1 root root 593 Mar 15 2017 dbus
. . .
. . .
-rw-r--r-- 1 root root 705 Mar 15 2017 web-data
-rw-r--r-- 1 root root 739 Mar 15 2017 winbind
-rw-r--r-- 1 root root 585 Mar 15 2017 wutmp
-rw-r--r-- 1 root root 1819 Mar 15 2017 X
-rw-r--r-- 1 root root 883 Mar 15 2017 xad
-rw-r--r-- 1 root root 673 Mar 15 2017 xdg-desktop
donnie@ubuntu3:/etc/apparmor.d/abstractions$
为了了解 AppArmor 规则的工作原理,让我们来看看 web-data 抽象文件的内容:
/srv/www/htdocs/ r,
/srv/www/htdocs/** r,
# virtual hosting
/srv/www/vhosts/ r,
/srv/www/vhosts/** r,
# mod_userdir
@{HOME}/public_html/ r,
@{HOME}/public_html/** r,
/srv/www/rails/*/public/ r,
/srv/www/rails/*/public/** r,
/var/www/html/ r,
/var/www/html/** r,
这个文件只是一个允许 Apache 守护程序读取文件的目录列表。让我们来分解一下:
-
请注意,每个规则都以
r,
结尾。这表示我们希望 Apache 对每个列出的目录具有读取权限。还要注意,每个规则都必须以逗号结尾。 -
/srv/www/htdocs/ r,
意味着列出的目录本身对于 Apache 具有读取权限。 -
/srv/www.htdocs/* * r,
* *
通配符使此规则递归。换句话说,Apache 可以读取指定目录的所有子目录中的所有文件。 -
mod_userdir 如果安装了,这个 Apache 模块允许 Apache 从用户家目录中的子目录读取网页内容文件。接下来的两行与此相关。
-
@{HOME}/public_html/ r,
和@{HOME}/public_html/ r,
@{HOME}
变量允许此规则与任何用户的家目录一起工作。(您将在/etc/apparmor.d/tunables/home
文件中看到此变量的定义。) -
请注意,没有特定的规则禁止 Apache 从其他位置读取。只是理解到这里未列出的任何内容对于 Apache web 服务器守护程序来说是禁止的。
tunables
子目录包含具有预定义变量的文件。您还可以使用此目录来定义新变量或进行配置文件调整:
donnie@ubuntu3:/etc/apparmor.d/tunables$ ls -l
total 56
-rw-r--r-- 1 root root 624 Mar 15 2017 alias
-rw-r--r-- 1 root root 376 Mar 15 2017 apparmorfs
-rw-r--r-- 1 root root 804 Mar 15 2017 dovecot
-rw-r--r-- 1 root root 694 Mar 15 2017 global
-rw-r--r-- 1 root root 983 Mar 15 2017 home
drwxr-xr-x 2 root root 4096 Oct 29 15:21 home.d
-rw-r--r-- 1 root root 792 Mar 15 2017 kernelvars
-rw-r--r-- 1 root root 631 Mar 15 2017 multiarch
drwxr-xr-x 2 root root 4096 Mar 15 2017 multiarch.d
-rw-r--r-- 1 root root 440 Mar 15 2017 proc
-rw-r--r-- 1 root root 430 Mar 15 2017 securityfs
-rw-r--r-- 1 root root 368 Mar 15 2017 sys
-rw-r--r-- 1 root root 868 Mar 15 2017 xdg-user-dirs
drwxr-xr-x 2 root root 4096 Oct 29 15:02 xdg-user-dirs.d
donnie@ubuntu3:/etc/apparmor.d/tunables$
空间不允许我向您展示如何从头开始编写自己的配置文件的细节,而且由于我们将在下一节中看到的一套实用程序,您可能永远不需要这样做。不过,为了让您更好地了解 AppArmor 的工作原理,这里有一些示例规则的图表,您可能会在任何给定的配置文件中找到:
/var/run/some_program.pid rw, |
进程将对此进程 ID 文件具有读取和写入权限。 |
---|---|
/etc/ld.so.cache r, |
进程将对此文件具有读取权限。 |
/tmp/some_program.* l, |
进程将能够创建和删除具有some_program 名称的链接。 |
/bin/mount ux |
进程对mount 实用程序具有可执行权限,然后将无限制地运行。(无限制意味着没有 AppArmor 配置文件。) |
使用 AppArmor 命令行实用程序
您是否拥有所需的所有 AppArmor 实用程序将取决于您使用的 Linux 发行版。在我的 OpenSUSE Leap 工作站上,这些实用程序已经预装好了。在我的 Ubuntu Server 虚拟机上,我不得不自己安装它们:
sudo apt install apparmor-utils
首先,让我们来看一下 Ubuntu 机器上 AppArmor 的状态:
donnie@ubuntu5:~$ sudo aa-status
[sudo] password for donnie:
apparmor module is loaded.
13 profiles are loaded.
13 profiles are in enforce mode.
/sbin/dhclient
/usr/bin/lxc-start
/usr/lib/NetworkManager/nm-dhcp-client.action
/usr/lib/NetworkManager/nm-dhcp-helper
/usr/lib/connman/scripts/dhclient-script
/usr/lib/snapd/snap-confine
/usr/lib/snapd/snap-confine//mount-namespace-capture-helper
/usr/sbin/mysqld
/usr/sbin/tcpdump
lxc-container-default
lxc-container-default-cgns
lxc-container-default-with-mounting
lxc-container-default-with-nesting
0 profiles are in complain mode.
1 processes have profiles defined.
1 processes are in enforce mode.
/usr/sbin/mysqld (679)
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
donnie@ubuntu5:~$
这里首先要注意的是,AppArmor 有强制模式和投诉模式。强制模式与 SELinux 中的强制模式执行相同的工作。它阻止系统进程执行活动策略不允许的操作,并记录任何违规行为。投诉模式与 SELinux 中的宽容模式相同。它允许进程执行活动策略禁止的操作,但会记录这些操作,记录在/var/log/audit/audit.log
文件中,或者系统日志文件中,具体取决于您是否安装了auditd
。(与红帽类型的发行版不同,auditd
在 Ubuntu 上默认情况下不会安装。)您可以使用投诉模式来帮助故障排除或测试新配置文件。
我们在这里看到的大多数强制模式配置文件都与网络管理或lxc
容器管理有关。我们看到的两个例外是snapd
的两个配置文件,它是使 snap 打包技术工作的守护程序。第三个例外是mysqld
配置文件。
Snap 软件包是设计用于多个发行版的通用二进制文件。Snap 技术目前适用于 Ubuntu 和 Fedora。
奇怪的是,当您在 Ubuntu 上安装守护程序包时,有时会得到该守护程序的预定义配置文件,有时则不会。即使配置文件随您安装的软件包一起提供,有时已经处于强制模式,有时则没有。例如,如果您正在设置域名服务(DNS)服务器并安装了bind9
软件包,您将获得一个已经处于强制模式的 AppArmor 配置文件。如果您正在设置数据库服务器并安装了mysql-server
软件包,您还将获得一个已经处于强制模式的工作配置文件。
但是,如果您正在设置数据库服务器并且更喜欢安装mariadb-server
而不是mysql-server
,您将获得一个完全禁用且无法启用的 AppArmor 配置文件。当您查看与mariadb-server
软件包一起安装的usr.sbin.mysqld
配置文件时,您会看到这样的内容:
# This file is intensionally empty to disable apparmor by default for newer
# versions of MariaDB, while providing seamless upgrade from older versions
# and from mysql, where apparmor is used.
#
# By default, we do not want to have any apparmor profile for the MariaDB
# server. It does not provide much useful functionality/security, and causes
# several problems for users who often are not even aware that apparmor
# exists and runs on their system.
#
# Users can modify and maintain their own profile, and in this case it will
# be used.
#
# When upgrading from previous version, users who modified the profile
# will be promptet to keep or discard it, while for default installs
# we will automatically disable the profile.
好吧,显然,AppArmor 并不适用于所有情况。(而且,写这篇文章的人需要上拼写课。)
然后,还有 Samba,它在很多方面都是一个特例。当您安装samba
软件包设置 Samba 服务器时,您根本不会得到任何 AppArmor 配置文件。对于 Samba 和其他一些不同的应用程序,您需要单独安装 AppArmor 配置文件:
sudo apt install apparmor-profiles apparmor-profiles-extras
安装这两个配置文件包时,所有配置文件都将处于投诉模式。这没关系,因为我们有一个方便的实用程序可以将它们置于强制模式。由于 Samba 有两个不同的守护程序需要保护,因此我们需要将两个不同的配置文件放置到强制模式中:
donnie@ubuntu5:/etc/apparmor.d$ ls *mbd
usr.sbin.nmbd usr.sbin.smbd
donnie@ubuntu5:/etc/apparmor.d$
我们将使用aa-enforce
来激活这两个配置文件的强制模式:
donnie@ubuntu5:/etc/apparmor.d$ sudo aa-enforce /usr/sbin/nmbd usr.sbin.nmbd
Setting /usr/sbin/nmbd to enforce mode.
Setting /etc/apparmor.d/usr.sbin.nmbd to enforce mode.
donnie@ubuntu5:/etc/apparmor.d$ sudo aa-enforce /usr/sbin/smbd usr.sbin.smbd
Setting /usr/sbin/smbd to enforce mode.
Setting /etc/apparmor.d/usr.sbin.smbd to enforce mode.
donnie@ubuntu5:/etc/apparmor.d$
要使用aa-enforce
,首先需要指定要保护的进程的可执行文件的路径。(幸运的是,通常你甚至不需要查找,因为路径名通常是配置文件的一部分。)命令的最后一部分是配置文件的名称。请注意,您需要重新启动 Samba 守护程序才能使 AppArmor 保护生效。
将配置文件放入其他模式同样简单。您只需要用需要使用的模式的实用程序替换aa-enforce
实用程序。以下是其他模式的实用程序的图表:
aa-audit |
审计模式与强制模式相同,只是允许的操作也会被记录,以及被阻止的操作。(强制模式只记录被阻止的操作。) |
---|---|
aa-disable |
这将完全禁用配置文件。 |
aa-complain |
这将配置文件置于投诉模式。 |
故障排除 AppArmor 问题
所以,我在过去的几天里一直在这里绞尽脑汁,试图想出一个好的故障排除方案。结果我并不需要。Ubuntu 的人民已经为我提供了一个完美的故障排除场景,以有缺陷的 Samba 配置文件的形式。
正如你刚刚看到的,我使用aa-enforce
将两个与 Samba 相关的配置文件置于强制模式。但是,现在当我尝试重新启动 Samba 以使配置文件生效时,看看会发生什么:
donnie@ubuntu3:/etc/apparmor.d$ sudo systemctl restart smbd
Job for smbd.service failed because the control process exited with error code. See "systemctl status smbd.service" and "journalctl -xe" for details.
donnie@ubuntu3:/etc/apparmor.d$
好吧,这不太好。查看smbd
服务的状态,我看到了这个:
donnie@ubuntu3:/etc/apparmor.d$ sudo systemctl status smbd
● smbd.service - LSB: start Samba SMB/CIFS daemon (smbd)
Loaded: loaded (/etc/init.d/smbd; bad; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2017-12-05 14:56:35 EST; 13s ago
Docs: man:systemd-sysv-generator(8)
Process: 31160 ExecStop=/etc/init.d/smbd stop (code=exited, status=0/SUCCESS)
Process: 31171 ExecStart=/etc/init.d/smbd start (code=exited, status=1/FAILURE)
Dec 05 14:56:35 ubuntu3 systemd[1]: Starting LSB: start Samba SMB/CIFS daemon (smbd)...
Dec 05 14:56:35 ubuntu3 smbd[31171]: * Starting SMB/CIFS daemon smbd
Dec 05 14:56:35 ubuntu3 smbd[31171]: ...fail!
Dec 05 14:56:35 ubuntu3 systemd[1]: smbd.service: Control process exited, code=exited status=1
Dec 05 14:56:35 ubuntu3 systemd[1]: Failed to start LSB: start Samba SMB/CIFS daemon (smbd).
Dec 05 14:56:35 ubuntu3 systemd[1]: smbd.service: Unit entered failed state.
Dec 05 14:56:35 ubuntu3 systemd[1]: smbd.service: Failed with result 'exit-code'.
donnie@ubuntu3:/etc/apparmor.d$
这里需要注意的重要事情是所有出现“失败”一词形式的地方。
原始错误消息说要使用journalctl -xe
查看日志消息。但是,journalctl
有一个坏习惯,会在屏幕右侧截断输出行。因此,我将使用less
或tail
来查看常规的/var/log/syslog
日志文件:
Dec 5 20:09:10 ubuntu3 smbd[14599]: * Starting SMB/CIFS daemon smbd
Dec 5 20:09:10 ubuntu3 kernel: [174226.392671] audit: type=1400 audit(1512522550.765:510): apparmor="DENIED" operation="mknod" profile="/usr/sbin/smbd" name="/run/samba/msg.
lock/14612" pid=14612 comm="smbd" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
Dec 5 20:09:10 ubuntu3 smbd[14599]: ...fail!
Dec 5 20:09:10 ubuntu3 systemd[1]: smbd.service: Control process exited, code=exited status=1
Dec 5 20:09:10 ubuntu3 systemd[1]: Failed to start LSB: start Samba SMB/CIFS daemon (smbd).
Dec 5 20:09:10 ubuntu3 systemd[1]: smbd.service: Unit entered failed state.
Dec 5 20:09:10 ubuntu3 systemd[1]: smbd.service: Failed with result 'exit-code'.
因此,我们看到apparmor=DENIED
。显然,Samba 正在尝试执行配置文件不允许的操作。Samba 需要将临时文件写入/run/samba/msg.lock
目录,但它没有被允许。我猜测配置文件缺少一个允许这种情况发生的规则。
但即使这个日志文件条目给我没有任何线索,我也可以使用一个多年来一直为我服务良好的故障排除技术来作弊。也就是说,我可以将日志文件中的错误消息复制粘贴到我最喜欢的搜索引擎中。几乎每次我这样做,我都发现其他人在我之前已经遇到了同样的问题:
好吧,我没有粘贴整个错误消息,但我粘贴了足够让 DuckDuckGo 处理。结果,它奏效了:
嗯,看起来我的配置文件可能缺少一行重要的内容。因此,我将打开usr.sbin.smbd
文件,并将此行放在规则集的末尾:
/run/samba/** rw,
这行将允许读写访问/run/samba
目录中的所有内容。编辑后,我需要重新加载此配置文件,因为它已经被aa-enforce
加载。为此,我将使用apparmor_parser
实用程序:
donnie@ubuntu3:/etc/apparmor.d$ sudo apparmor_parser -r usr.sbin.smbd
donnie@ubuntu3:/etc/apparmor.d$
你只需要使用-r
选项重新加载并列出配置文件的名称。现在,让我们尝试重新启动 Samba:
donnie@ubuntu3:/etc/apparmor.d$ sudo systemctl restart smbd
donnie@ubuntu3:/etc/apparmor.d$ sudo systemctl status smbd
● smbd.service - LSB: start Samba SMB/CIFS daemon (smbd)
Loaded: loaded (/etc/init.d/smbd; bad; vendor preset: enabled)
Active: active (running) since Wed 2017-12-06 13:31:32 EST; 3min 6s ago
Docs: man:systemd-sysv-generator(8)
Process: 17317 ExecStop=/etc/init.d/smbd stop (code=exited, status=0/SUCCESS)
Process: 16474 ExecReload=/etc/init.d/smbd reload (code=exited, status=0/SUCCESS)
Process: 17326 ExecStart=/etc/init.d/smbd start (code=exited, status=0/SUCCESS)
Tasks: 3
Memory: 9.3M
CPU: 594ms
CGroup: /system.slice/smbd.service
├─17342 /usr/sbin/smbd -D
├─17343 /usr/sbin/smbd -D
└─17345 /usr/sbin/smbd -D
Dec 06 13:31:28 ubuntu3 systemd[1]: Stopped LSB: start Samba SMB/CIFS daemon (smbd).
Dec 06 13:31:28 ubuntu3 systemd[1]: Starting LSB: start Samba SMB/CIFS daemon (smbd)...
Dec 06 13:31:32 ubuntu3 smbd[17326]: * Starting SMB/CIFS daemon smbd
Dec 06 13:31:32 ubuntu3 smbd[17326]: ...done.
Dec 06 13:31:32 ubuntu3 systemd[1]: Started LSB: start Samba SMB/CIFS daemon (smbd).
donnie@ubuntu3:/etc/apparmor.d$
而且,它奏效了。两个 Samba 配置文件都处于强制模式,Samba 终于正常启动了。
奇怪的是,我在 Ubuntu 16.04 和 Ubuntu 17.10 都遇到了同样的问题。因此,这个错误已经存在很长时间了,而且似乎 Ubuntu 的人们要么不知道它,要么不愿意修复它。在某种程度上,我希望它永远不会被修复,因为修复它会破坏我完美的培训演示。
总结
在本章中,我们了解了强制访问控制的基本原则,并比较了两种不同的强制访问控制系统。我们看到了 SELinux 和 AppArmor 是什么,以及它们如何帮助保护系统免受恶意行为者的侵害。然后,我们看了如何使用它们的基础知识以及如何对它们进行故障排除的基础知识。我们还看到,尽管它们都是为了完成同样的工作,但它们的工作方式却大不相同。
无论您是使用 AppArmor 还是 SELinux,您都希望在将新系统置于投诉或宽松模式之前对其进行彻底测试,然后再投入生产。确保您想要保护的内容得到保护,同时允许您想要允许的内容得到允许。将机器投入生产后,不要假设您可以在每次看到策略违规时自动更改策略设置。可能是您的强制访问控制设置没有问题,MAC 只是在保护您免受坏人的侵害。
这两个主题都有很多内容,我们无法在这里全部涵盖。不过希望我已经给了你足够的启发,足够帮助你在日常工作中。
在下一章中,我们将讨论扫描、审计和加固。我会在那里见到你。
第八章:扫描、审计和加固
一个常见的误解是 Linux 用户永远不需要担心恶意软件。是的,Linux 比 Windows 更抵抗病毒。但是,病毒只是恶意软件的一种类型,其他类型的恶意软件也可以植入 Linux 机器。而且,如果您运行的服务器将与 Windows 用户共享文件,您将希望确保不与他们共享任何感染病毒的文件。
虽然 Linux 系统日志文件很好,但它们并不总是能清楚地反映谁做了什么或者谁访问了什么。可能是入侵者或内部人员试图访问未经授权的数据。我们真正想要的是一个良好的审计系统,可以在人们做了不应该做的事情时向我们发出警报。
然后,还有合规性的问题。您的组织可能必须与一个或多个规制机构打交道,这些机构规定了您如何加固服务器以防止攻击。如果您不符合规定,可能会被罚款或被迫停业。
幸运的是,我们有办法解决所有这些问题,而且它们并不那么复杂。
在本章中,我们将涵盖以下主题:
-
安装和更新 ClamAV 和 maldet
-
使用 ClamAV 和 maldet 进行扫描
-
SELinux 考虑
-
使用 Rootkit Hunter 扫描 rootkits
-
控制 auditd 守护程序
-
创建审计规则
-
使用
ausearch
和aureport
实用程序搜索审计日志中的问题 -
oscap
,命令行实用程序,用于管理和应用 OpenSCAP 策略 -
OpenSCAP Workbench,用于管理和应用 OpenSCAP 策略的 GUI 实用程序
-
OpenSCAP 策略文件及其各自旨在满足的合规标准
-
在操作系统安装期间应用策略
安装和更新 ClamAV 和 maldet
尽管我们不必过多担心病毒感染我们的 Linux 机器,但我们确实需要担心与 Windows 用户共享感染文件的问题。ClamAV 是一个可以作为独立程序运行或集成到邮件服务器守护程序(如 Postfix)中的自由开源软件(FOSS)防病毒解决方案。它是一个传统的防病毒扫描程序,工作方式基本与典型的 Windows 工作站上的防病毒程序相同。包含的freshclam
实用程序允许您更新病毒签名。
Linux Malware Detect,通常缩写为LMD或maldet,是另一个可以与 ClamAV 一起工作的 FOSS 防病毒程序。(为了节省输入,我现在只会称它为 LMD。)据我所知,它并不在任何 Linux 发行版的存储库中,但安装和配置起来仍然很简单。其特点之一是当它在网络的边缘入侵检测系统上看到恶意软件时,它会自动生成恶意软件检测签名。最终用户也可以提交自己的恶意软件样本。安装后,您将获得一个已启用的 systemd 服务和一个定期更新恶意软件签名和程序本身的 cron 作业。它利用 Linux 内核的 inotify 功能自动监视目录中已更改的文件。安装它的过程对于任何基于 systemd 的 Linux 发行版来说基本相同。
您可以在以下网址获取有关 Linux Malware Detect 的所有细节:
www.rfxn.com/projects/linux-malware-detect/.
我们安装 ClamAV 和 LMD 的原因是,正如 LMD 的开发人员自由承认的那样,ClamAV 扫描引擎在扫描大文件集时性能更好。而且,通过将它们放在一起,ClamAV 可以使用 LMD 恶意软件签名以及自己的恶意软件签名。
安装 ClamAV 和 maldet
我们将从安装 ClamAV 开始。(它在 Ubuntu 的正常软件库中,但不在 CentOS 中。对于 CentOS,您需要安装 EPEL 软件库,就像我在第一章中所示的那样,在虚拟环境中运行 Linux。)我们还将安装 Wget,我们将用它来下载 LMD。
以下命令将帮助您在 Ubuntu 上安装 ClamAV 和 Wget:
donnie@ubuntu3:~$ sudo apt install clamav wget
以下命令将帮助您在 CentOS 上安装 ClamAV 和 Wget:
[donnie@localhost ~]$ sudo yum install clamav clamav-update wget
对于 Ubuntu,clamav
软件包包含您所需的一切。对于 CentOS,您还需要安装clamav-update
以获取病毒更新。
其余步骤对于任何虚拟机都是相同的。
接下来,您将下载并安装 LMD。在这里,您将要做一件我很少告诉人们要做的事情。也就是说,您将要登录到根用户 shell。原因是,尽管 LMD 安装程序可以使用 sudo 正常工作,但您最终会发现程序文件的所有者是执行安装的用户,而不是根用户。从根用户的 shell 中执行安装可以避免我们跟踪这些文件并更改所有权的麻烦。因此,按照以下方式下载文件:
sudo su -
wget http://www.rfxn.com/downloads/maldetect-current.tar.gz
现在,您将在根用户的主目录中找到该文件。现在,解压缩存档,进入生成的目录,并运行安装程序。安装程序完成后,将README
文件复制到您自己的主目录,以便随时参考。(此README
文件是 LMD 的文档。)然后,从根用户的 shell 退出到您自己的 shell:
tar xzvf maldetect-current.tar.gz
cd maldetect-1.6.2/
root@ubuntu3:~/maldetect-1.6.2# ./install.sh
Created symlink from /etc/systemd/system/multi-user.target.wants/maldet.service to /usr/lib/systemd/system/maldet.service.
update-rc.d: error: initscript does not exist: /etc/init.d/maldet
Linux Malware Detect v1.6
(C) 2002-2017, R-fx Networks <proj@r-fx.org>
(C) 2017, Ryan MacDonald <ryan@r-fx.org>
This program may be freely redistributed under the terms of the GNU GPL
installation completed to /usr/local/maldetect
config file: /usr/local/maldetect/conf.maldet
exec file: /usr/local/maldetect/maldet
exec link: /usr/local/sbin/maldet
exec link: /usr/local/sbin/lmd
cron.daily: /etc/cron.daily/maldet
maldet(22138): {sigup} performing signature update check...
maldet(22138): {sigup} local signature set is version 2017070716978
maldet(22138): {sigup} new signature set (201708255569) available
maldet(22138): {sigup} downloading https://cdn.rfxn.com/downloads/maldet-sigpack.tgz
maldet(22138): {sigup} downloading https://cdn.rfxn.com/downloads/maldet-cleanv2.tgz
maldet(22138): {sigup} verified md5sum of maldet-sigpack.tgz
maldet(22138): {sigup} unpacked and installed maldet-sigpack.tgz
maldet(22138): {sigup} verified md5sum of maldet-clean.tgz
maldet(22138): {sigup} unpacked and installed maldet-clean.tgz
maldet(22138): {sigup} signature set update completed
maldet(22138): {sigup} 15218 signatures (12485 MD5 | 1954 HEX | 779 YARA | 0 USER)
root@ubuntu3:~/maldetect-1.6.2# cp README /home/donnie
root@ubuntu3:~/maldetect-1.6.2# exit
logout
donnie@ubuntu3:~$
正如您所看到的,安装程序会自动创建符号链接以启用 maldet 服务,并且还会自动下载并安装最新的恶意软件签名。
配置 maldet
如果您在此时尝试启动 maldet 服务,它将失败。要使其工作,您需要配置要自动监视和扫描的目录。为此,您将把这些目录添加到/usr/local/maldetect/monitor_paths
文件中。目前,我只想监视/home
和/root
目录,所以我的monitor_paths
文件看起来是这样的:
/home
/root
保存文件后,您就可以启动 maldet 守护程序了:
sudo systemctl start maldet
您可以随时向monitor_paths
文件添加更多目录,但请记住每次这样做时都要重新启动 maldet 守护程序,以便读取新添加的内容。
LMD 的配置文件是/usr/local/maldetect/conf.maldet
。它有非常完善的文档和对每个配置项都有良好的注释,因此您不应该有任何困难来弄清楚它。目前,我们只会做一些配置更改。
在文件顶部,启用电子邮件警报并将您的用户名设置为电子邮件地址。现在,这两行应该看起来像这样:
email_alert="1"
email_addr="donnie"
LMD 尚未配置为将可疑文件移动到隔离文件夹中,我们希望它这样做。打开您的文本编辑器中的conf.maldet
文件,并查找以下行:
quarantine_hits="0"
将上一行更改为以下行:
quarantine_hits="1"
您将看到一些其他可以配置的隔离操作,但目前这就是我们需要的全部。保存文件后,重新启动 maldet:
sudo systemctl restart maldet
新更改现在将生效。
更新 ClamAV 和 maldet
对于忙碌的管理员来说,好消息是您不必做任何事情来保持这两个程序的更新。它们都通过自动创建的 cron 作业运行,并为我们进行更新。为了证明 ClamAV 正在更新,我们可以查看系统日志文件:
Dec 8 20:02:09 localhost freshclam[22326]: ClamAV update process started at Fri Dec 8 20:02:09 2017
Dec 8 20:02:29 localhost freshclam[22326]: Can't query current.cvd.clamav.net
Dec 8 20:02:29 localhost freshclam[22326]: Invalid DNS reply. Falling back to HTTP mode.
Dec 8 20:02:29 localhost freshclam[22326]: Reading CVD header (main.cvd):
Dec 8 20:02:35 localhost freshclam[22326]: OK
Dec 8 20:02:47 localhost freshclam[22326]: Downloading main-58.cdiff [100%]
Dec 8 20:03:19 localhost freshclam[22326]: main.cld updated (version: 58, sigs: 4566249, f-level: 60, builder: sigmgr)
. . .
. . .
Dec 8 20:04:45 localhost freshclam[22326]: Downloading daily.cvd [100%]
Dec 8 20:04:53 localhost freshclam[22326]: daily.cvd updated (version: 24111, sigs: 1799769, f-level: 63, builder: neo)
Dec 8 20:04:53 localhost freshclam[22326]: Reading CVD header (bytecode.cvd):
Dec 8 20:04:54 localhost freshclam[22326]: OK
Dec 8 20:04:54 localhost freshclam[22326]: Downloading bytecode-279.cdiff [100%]
Dec 8 20:04:55 localhost freshclam[22326]: Downloading bytecode-280.cdiff [100%]
Dec 8 20:04:55 localhost freshclam[22326]: Downloading bytecode-281.cdiff [100%]
Dec 8 20:04:56 localhost freshclam[22326]: Downloading bytecode-282.cdiff [100%]
. . .
. . .
您将在 Ubuntu 日志或 CentOS 日志中看到相同的条目。但是,自动运行更新的方式有所不同。
在您的 Ubuntu 机器的/etc/clamav/freshclam.conf
文件中,您会在末尾看到以下行:
# Check for new database 24 times a day
Checks 24
DatabaseMirror db.local.clamav.net
DatabaseMirror database.clamav.net
因此,基本上这意味着在 Ubuntu 上,ClamAV 将每小时检查更新。
在您的 CentOS 机器上,您将在/etc/cron.d
目录中看到一个clamav-update
cron 作业,如下所示:
## Adjust this line...
MAILTO=root
## It is ok to execute it as root; freshclam drops privileges and becomes
## user 'clamupdate' as soon as possible
0 */3 * * * root /usr/share/clamav/freshclam-sleep
左侧第二列中的*/3
表示 ClamAV 将每 3 小时检查更新。如果您愿意,可以更改该设置,但您还需要更改/etc/sysconfig/freshclam
文件中的设置。假设您希望 CentOS 每小时检查一次 ClamAV 更新。在 cron 作业文件中,将*/3
更改为*
。(您不需要执行*/1
,因为该位置上的星号已经表示作业将每小时运行一次。)然后,在/etc/sysconfig/freshclam
文件中查找以下行:
# FRESHCLAM_MOD=
取消注释该行,并添加您希望更新之间的分钟数。要设置为 1 小时,以匹配 cron 作业,它将如下所示:
FRESHCLAM_MOD=60
为了证明 maldet 正在更新,您可以查看/usr/local/maldetect/logs/
目录中的其自己的日志文件。在event_log
文件中,您将看到以下代码:
Dec 06 22:06:14 localhost maldet(3728): {sigup} performing signature update check...
Dec 06 22:06:14 localhost maldet(3728): {sigup} local signature set is version 2017070716978
Dec 06 22:07:13 localhost maldet(3728): {sigup} downloaded https://cdn.rfxn.com/downloads/maldet.sigs.ver
Dec 06 22:07:13 localhost maldet(3728): {sigup} new signature set (201708255569) available
Dec 06 22:07:13 localhost maldet(3728): {sigup} downloading https://cdn.rfxn.com/downloads/maldet-sigpack.tgz
. . .
. . .
Dec 06 22:07:43 localhost maldet(3728): {sigup} unpacked and installed maldet-clean.tgz
Dec 06 22:07:43 localhost maldet(3728): {sigup} signature set update completed
Dec 06 22:07:43 localhost maldet(3728): {sigup} 15218 signatures (12485 MD5 | 1954 HEX | 779 YARA | 0 USER)
Dec 06 22:14:55 localhost maldet(4070): {scan} signatures loaded: 15218 (12485 MD5 | 1954 HEX | 779 YARA | 0 USER)
在/usr/local/maldetect/conf.maldet
文件中,您将看到以下两行,但它们之间有一些注释:
autoupdate_signatures="1"
autoupdate_version="1"
LMD 不仅会自动更新其恶意软件签名,还会确保您拥有 LMD 本身的最新版本。
使用 ClamAV 和 maldet 进行扫描
LMD 的 maldet 守护程序会不断监视您在/usr/local/maldetect/monitor_paths
文件中指定的目录。当它发现可能是恶意软件的文件时,它会自动执行您在conf.maldet
文件中指定的操作。为了演示其工作原理,我将在我的主目录中创建一个模拟恶意软件文件。幸运的是,这比听起来要容易,因为我们有一个网站可以帮助我们。
EICAR,以前以其全名European Institute for Computer Antivirus Research而闻名,提供了一个病毒签名,您可以将其包含在一个纯文本文件中。您可以在以下网址获取:www.eicar.org/86-0-Intended-use.html
。
要创建模拟病毒文件,请转到我在前面链接中列出的页面。
向下滚动页面,直到在文本框中看到以下文本行:
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
复制该文本行并将其插入到一个文本文件中,然后将其保存到任一虚拟机的主目录中。(您可以随意命名,但我会将其命名为testing.txt
。)等待片刻,您会看到文件消失。然后,查看/usr/local/maldetect/logs/event_log
文件,以验证 LMD 是否将文件移至隔离区:
Dec 09 19:03:43 localhost maldet(7192): {quar} malware quarantined from '/home/donnie/testing.txt' to '/usr/local/maldetect/quarantine/testing.txt.89513558'
LMD 还有更多内容,这里无法全部展示。但是,您可以在随附的README
文件中了解所有内容。
SELinux 注意事项
以前,在 Red Hat 类型的系统上进行杀毒扫描会触发 SELinux 警报。但是,在校对本章的过程中,扫描都按照预期进行,SELinux 从未打扰过我。因此,这个问题似乎已经解决了。
如果您在病毒扫描中生成任何 SELinux 警报,只需更改一个布尔值即可解决问题:
[donnie@localhost ~]$ getsebool -a | grep 'virus'
antivirus_can_scan_system --> off
antivirus_use_jit --> off
[donnie@localhost ~]$
我们感兴趣的是antivirus_can_scan_system
布尔值,默认情况下是关闭的。要打开以启用病毒扫描,请按照以下步骤:
[donnie@localhost ~]$ sudo setsebool -P antivirus_can_scan_system on
[sudo] password for donnie:
[donnie@localhost ~]$ getsebool antivirus_can_scan_system
antivirus_can_scan_system --> on
[donnie@localhost ~]$
这应该解决您可能遇到的与 SELinux 相关的扫描问题。但是,就目前情况而言,您可能不需要担心它。
使用 Rootkit Hunter 扫描 rootkits
rootkit 是极其恶毒的恶意软件,绝对会毁了你的一天。它们可以监听来自他们主人的命令,窃取敏感数据并将其发送给他们的主人,或者为他们的主人提供一个易于访问的后门。它们被设计为隐秘的,具有隐藏自己的能力。有时,它们会用自己的特洛伊木马版本替换诸如ls
或ps
之类的实用程序,这些实用程序将显示系统上的所有文件或进程,但不包括与 rootkit 相关的文件。Rootkit 可以感染任何操作系统,甚至是我们心爱的 Linux。
为了植入 rootkit,攻击者必须已经在系统上获得了管理员权限。这是我总是在看到人们都在 root 用户的 shell 中完成所有工作时感到不安的许多原因之一,也是我坚决主张尽可能使用 sudo 的原因。我是说,真的,我们为什么要让坏人轻而易举地得逞呢?
几年前,在 Windows XP 的黑暗时期,索尼音乐因为有人发现他们在音乐 CD 上植入了 rootkit 而陷入了一些麻烦。他们并不是有意要做任何恶意的事情,只是想阻止人们使用他们的计算机制作非法副本。当然,大多数人都以管理员帐户运行 Windows XP,这使得 rootkit 很容易感染他们的计算机。Windows 用户仍然大多以管理员帐户运行,但至少现在有用户访问控制来帮助缓解这些问题。
有几个不同的程序可以扫描 rootkit,两者使用方式基本相同。我们现在要看的是一个名为 Rootkit Hunter 的程序。
安装和更新 Rootkit Hunter
对于 Ubuntu,Rootkit Hunter 在正常的存储库中。对于 CentOS,您需要安装 EPEL 存储库,就像我在第一章中所示的那样,在虚拟环境中运行 Linux。对于这两个 Linux 发行版,软件包名称是rkhunter
。
对于 Ubuntu:
sudo apt install rkhunter
对于 CentOS:
sudo yum install rkhunter
安装后,您可以使用以下命令查看其选项:
man rkhunter
简单,对吧?
接下来,您需要使用--update
选项更新 rootkit 签名:
[donnie@localhost ~]$ sudo rkhunter --update
[ Rootkit Hunter version 1.4.4 ]
Checking rkhunter data files...
Checking file mirrors.dat [ Updated ]
Checking file programs_bad.dat [ Updated ]
Checking file backdoorports.dat [ No update ]
Checking file suspscan.dat [ Updated ]
Checking file i18n/cn [ No update ]
Checking file i18n/de [ Updated ]
Checking file i18n/en [ Updated ]
Checking file i18n/tr [ Updated ]
Checking file i18n/tr.utf8 [ Updated ]
Checking file i18n/zh [ Updated ]
Checking file i18n/zh.utf8 [ Updated ]
Checking file i18n/ja [ Updated ]
[donnie@localhost ~]$
现在,我们准备好扫描了。
扫描 rootkit
要运行扫描,请使用-c
选项。(这是用于检查的-c
。)请耐心等待,因为这需要一段时间:
sudo rkhunter -c
当您以这种方式运行扫描时,Rootkit Hunter 将定期停止并要求您按Enter键继续。扫描完成后,您会在/var/log
目录中找到一个rkhunter.log
文件。
要让 Rootkit Hunter 自动作为 cron 作业运行,您需要使用--cronjob
选项,这将导致程序一直运行下去,而不会提示您不断按Enter键。您可能还想使用--rwo
选项,这将导致程序仅报告警告,而不是报告所有良好的内容。从命令行,命令看起来是这样的:
sudo rkhunter -c --cronjob --rwo
要创建一个自动每晚运行 Rootkit Hunter 的 cron 作业,请打开 root 用户的 crontab 编辑器:
sudo crontab -e -u root
假设您想在每天晚上 10 点 20 分运行 Rootkit Hunter。将其输入到 crontab 编辑器中:
20 22 * * * /usr/bin/rkhunter -c --cronjob --rwo
由于 cron 只能使用 24 小时制时间,因此您必须将晚上 10:00 表示为 22。 (只需将您习惯使用的 P.M.时钟时间加 12 即可。)这三个星号分别表示该作业将在每个月的每一天,每个月和每周的每一天运行。您需要列出命令的完整路径,否则 cron 将无法找到它。
您可以在rkhunter
手册页中找到更多可能对您感兴趣的选项,但这应该足以让您开始使用它。
控制 auditd 守护程序
因此,您有一个充满了只有极少数人需要看到的绝密文件的目录,并且您想知道未经授权的人何时尝试查看它们。或者,也许您想知道某个文件何时被更改。或者,也许您想知道人们何时登录系统以及他们登录后在做什么。对于所有这些以及更多内容,您都有 auditd 系统。这是一个非常酷的系统,我相信您会喜欢它。
auditd 的美妙之一是它在 Linux 内核级别工作,而不是在用户模式级别。这使得攻击者更难以颠覆。
在红帽类型的系统上,auditd 默认已安装并启用。因此,您会在 CentOS 机器上找到它。在 Ubuntu 上,它尚未安装,因此您需要自己安装:
sudo apt install auditd
在 Ubuntu 上,您可以使用正常的systemctl
命令控制 auditd 守护程序。因此,如果需要重新启动 auditd 以读取新的配置,可以使用以下命令:
sudo systemctl restart auditd
在 CentOS 7 上,由于某种我不理解的原因,正常的systemctl
命令无法与 auditd 一起使用。(对于所有其他守护程序,它们可以。)因此,在您的 CentOS 7 机器上,您将使用老式的service
命令重新启动 auditd 守护程序,如下所示:
sudo service auditd restart
除了这个小的不同之外,我告诉你的关于 auditd 的一切都适用于 Ubuntu 和 CentOS。
创建审计规则
好的,让我们从简单的开始,逐步提升到令人惊叹的东西。首先,让我们检查是否有任何审计规则生效:
[donnie@localhost ~]$ sudo auditctl -l
[sudo] password for donnie:
No rules
[donnie@localhost ~]$
正如您所看到的,auditctl
命令是我们用来管理审计规则的命令。-l
选项列出规则。
审计文件的更改
现在,假设我们想要查看当有人更改/etc/passwd
文件时。 (我们将使用的命令看起来有点吓人,但我保证一旦我们分解它,它就会讲得通。)看看以下代码:
[donnie@localhost ~]$ sudo auditctl -w /etc/passwd -p wa -k passwd_changes
[sudo] password for donnie:
[donnie@localhost ~]$ sudo auditctl -l
-w /etc/passwd -p wa -k passwd_changes
[donnie@localhost ~]$
这是细节:
-
-w
:这代表着“在哪里”,并且指向我们想要监视的对象。在这种情况下,它是/etc/passwd
。 -
-p
:这表示我们要监视的对象的权限。在这种情况下,我们正在监视任何人尝试(w)写入文件或尝试进行(a)属性更改的情况。(我们可以审计的另外两个权限是(r)读取和 e(x)ecute。) -
-k
:k
代表 key,这只是 auditd 分配规则名称的方式。因此,passwd_changes
是我们正在创建的规则的键或名称。
auditctl -l
命令向我们显示规则确实存在。
现在,这个规则的一个小问题是它只是临时的,当我们重新启动机器时就会消失。要使其永久,我们需要在/etc/audit/rules.d/
目录中创建一个自定义规则文件。然后,当您重新启动 auditd 守护程序时,自定义规则将被插入到/etc/audit/audit.rules
文件中。因为/etc/audit/
目录只能被具有 root 权限的人访问,所以我将通过列出文件的完整路径来打开文件,而不是尝试进入目录:
sudo less /etc/audit/audit.rules
这个默认文件中没有太多内容:
## This file is automatically generated from /etc/audit/rules.d
-D
-b 8192
-f 1
这个文件的细节如下:
-
-D
:这将导致当前生效的所有规则和监视被删除,以便我们可以从干净的状态开始。因此,如果我现在重新启动 auditd 守护程序,它将读取这个audit.rules
文件,这将删除我刚刚创建的规则。 -
-b 8192
:这设置了我们可以同时拥有的未决审计缓冲区的数量。如果所有缓冲区都满了,系统将无法生成更多的审计消息。 -
-f 1
:这设置了关键错误的失败模式,值可以是 0、1 或 2。-f 0
会将模式设置为静默,这意味着 auditd 不会对关键错误采取任何措施。如我们在这里看到的-f 1
,告诉 auditd 只报告关键错误,-f 2
会导致 Linux 内核进入紧急模式。根据auditctl
手册页面,高安全环境中的任何人可能都想将其更改为-f 2
。但对于我们的目的,-f1
就可以了。
您可以使用文本编辑器在/etc/audit/rules.d/
目录中创建一个新的规则文件。或者,您可以将auditctl -l
输出重定向到一个新文件,就像这样:
[donnie@localhost ~]$ sudo sh -c "auditctl -l > /etc/audit/rules.d/custom.rules"
[donnie@localhost ~]$ sudo service auditd restart
由于 Bash shell 不允许我直接将信息重定向到/etc
目录中的文件,即使使用 sudo,我也必须使用sudo sh -c
命令来执行auditctl
命令。重新启动 auditd 守护程序后,我们的audit.rules
文件现在如下所示:
## This file is automatically generated from /etc/audit/rules.d
-D
-b 8192
-f 1
-w /etc/passwd -p wa -k passwd_changes
现在,规则将在每次机器重新启动时生效,以及每次手动重新启动 auditd 守护程序时生效。
审计目录
我的固体灰色小猫维基和灰白色虎斑小猫克利奥帕特拉有一些非常敏感的秘密需要保护。因此,我创建了secretcats
组并将它们添加到其中。然后,我创建了secretcats
共享目录,并按照我在第六章中向您展示的方式设置了它的访问控制列表:
[donnie@localhost ~]$ sudo groupadd secretcats
[sudo] password for donnie:
[donnie@localhost ~]$ sudo usermod -a -G secretcats vicky
[donnie@localhost ~]$ sudo usermod -a -G secretcats cleopatra
[donnie@localhost ~]$ sudo mkdir /secretcats
[donnie@localhost ~]$ sudo chown nobody:secretcats /secretcats/
[donnie@localhost ~]$ sudo chmod 3770 /secretcats/
[donnie@localhost ~]$ ls -ld /secretcats/
drwxrws--T. 2 nobody secretcats 6 Dec 11 14:47 /secretcats/
[donnie@localhost ~]$
维基和克利奥帕特拉希望绝对确定没有人能进入他们的东西,因此他们要求我为他们的目录设置审计规则:
[donnie@localhost ~]$ sudo auditctl -w /secretcats/ -k secretcats_watch
[sudo] password for donnie:
[donnie@localhost ~]$ sudo auditctl -l
-w /etc/passwd -p wa -k passwd_changes
-w /secretcats -p rwxa -k secretcats_watch
[donnie@localhost ~]$
与以前一样,-w
表示我们要监视的内容,-k
表示审计规则的名称。这次,我省略了-p
选项,因为我想监视每种类型的访问。换句话说,我想监视任何读取、写入、属性更改或执行操作。(因为这是一个目录,当有人尝试cd
到目录时,执行操作会发生。)您可以在auditctl -l
输出中看到,通过省略-p
,我们现在将监视一切。但是,假设我只想监视有人尝试cd
到这个目录的情况。相反,我可以使规则看起来像这样:
sudo auditctl -w /secretcats/ -p x -k secretcats_watch
到目前为止还算简单,对吧?现在让我们看看更复杂的东西。
审计系统调用
创建监视某个动作的规则并不难,但命令语法比我们到目前为止看到的要复杂一些。使用这个规则,我们将在查理尝试打开文件或尝试创建文件时收到警报:
[donnie@localhost ~]$ sudo auditctl -a always,exit -F arch=b64 -S openat -F auid=1006
[sudo] password for donnie:
[donnie@localhost ~]$ sudo auditctl -l
-w /etc/passwd -p wa -k passwd_changes
-w /secretcats -p rwxa -k secretcats_watch
-a always,exit -F arch=b64 -S openat -F auid=1006
[donnie@localhost ~]$
这是分解:
-
-a always,exit
:这里有动作和列表。exit
部分表示此规则将被添加到系统调用退出列表中。每当操作系统从系统调用退出时,将使用退出列表来确定是否需要生成审计事件。always
部分是动作,表示每次从指定系统调用退出时都会创建此规则的审计记录。请注意,动作和列表参数必须用逗号分隔。 -
-F arch=b64
:-F
选项用于构建规则字段,在此命令中我们看到两个规则字段。第一个规则字段指定了机器的 CPU 架构。b64
表示计算机正在使用 x86_64 CPU。(无论是英特尔还是 AMD 都无关紧要。)考虑到 32 位机器正在消失,Sun SPARC 和 PowerPC 机器并不常见,现在大多数情况下会看到b64
。 -
-S openat
:-S
选项指定我们要监视的系统调用。openat
是打开或创建文件的系统调用。 -
-F auid=1006
:这第二个审计字段指定了我们要监视的用户的用户 ID 号码。(查理的用户 ID 号码是1006
。)
关于系统调用或 syscalls 的完整解释对我们当前的目的来说有点太深奥了。现在,暂且可以说,每当用户发出请求 Linux 内核提供服务的命令时,就会发生系统调用。如果你有兴趣,可以在这里阅读更多关于 syscalls 的内容:blog.packagecloud.io/eng/2016/04/05/the-definitive-guide-to-linux-system-calls/
。
我在这里呈现的只是你可以使用审计规则做的许多事情中的一小部分。要查看更多示例,请查看auditctl
手册页:
man auditctl
所以,现在你在想,“既然我有了这些规则,我怎么知道有人试图违反它们呢?”像往常一样,我很高兴你问了。
使用 ausearch 和 aureport
auditd 守护程序将事件记录到/var/log/audit/audit.log
文件中。虽然你可以直接使用less
之类的工具读取文件,但你真的不想这样做。ausearch
和aureport
实用程序将帮助你将文件转换为一种有些意义的语言。
搜索文件更改警报
让我们首先看一下我们创建的规则,该规则将在对/etc/passwd
文件进行更改时警报我们:
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
现在,让我们对文件进行更改并查找警报消息。我不想再添加另一个用户,因为我已经用完了可以使用的猫的名字,所以我将使用chfn
实用程序来将联系信息添加到 Cleopatra 条目的注释字段中:
[donnie@localhost etc]$ sudo chfn cleopatra
Changing finger information for cleopatra.
Name []: Cleopatra Tabby Cat
Office []: Donnie's back yard
Office Phone []: 555-5555
Home Phone []: 555-5556
Finger information changed.
[donnie@localhost etc]
我现在将使用ausearch
查找此事件可能生成的任何审计消息:
[donnie@localhost ~]$ sudo ausearch -i -k passwd_changes
----
type=CONFIG_CHANGE msg=audit(12/11/2017 13:06:20.665:11393) : auid=donnie ses=842 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op=add_rule key=passwd_changes li
st=exit res=yes
----
type=CONFIG_CHANGE msg=audit(12/11/2017 13:49:15.262:11511) : auid=donnie ses=842 op=updated_rules path=/etc/passwd key=passwd_changes list=exit res=yes
[donnie@localhost ~]$
这是分解:
-
-i
:这将接受任何数字数据,并在可能的情况下将其转换为文本。在这种情况下,它接受用户 ID 号并将其转换为实际的用户名,显示为auid=donnie
。如果我不加-i
,用户信息将显示为auid=1000
,这是我的用户 ID 号。 -
-k passwd_changes
:这指定了我们想要查看审计消息的审计规则的键或名称。
你可以看到这个输出有两部分。第一部分只是显示我创建审计规则的时间,所以我们对此不感兴趣。在第二部分中,你可以看到我触发规则的时间,但它没有显示我如何触发它。所以,让我们使用aureport
来看看它是否会给我们更多线索:
[donnie@localhost ~]$ sudo aureport -i -k | grep 'passwd_changes'
1\. 12/11/2017 13:06:20 passwd_changes yes ? donnie 11393
2\. 12/11/2017 13:49:15 passwd_changes yes ? donnie 11511
3\. 12/11/2017 13:49:15 passwd_changes yes /usr/bin/chfn donnie 11512
4\. 12/11/2017 14:54:11 passwd_changes yes /usr/sbin/usermod donnie 11728
5\. 12/11/2017 14:54:25 passwd_changes yes /usr/sbin/usermod donnie 11736
[donnie@localhost ~]$
有趣的是,使用ausearch
时,你必须在-k
选项之后指定你感兴趣的审计规则的名称或键。而对于aureport
,-k
选项表示你想查看与所有审计规则键有关的所有日志条目。要查看特定键的日志条目,只需将输出导入 grep。-i
选项对ausearch
的作用与对aureport
的作用相同。
正如你所看到的,aureport
将audit.log
文件的隐晦语言解析为更容易理解的普通语言。我不确定我做了什么来生成事件 1 和 2,所以我查看了/var/log/secure
文件以查找答案。我在那些时间看到了这两个条目:
Dec 11 13:06:20 localhost sudo: donnie : TTY=pts/1 ; PWD=/home/donnie ; USER=root ; COMMAND=/sbin/auditctl -w /etc/passwd -p wa -k passwd_changes
. . .
. . .
Dec 11 13:49:24 localhost sudo: donnie : TTY=pts/1 ; PWD=/home/donnie ; USER=root ; COMMAND=/sbin/ausearch -i -k passwd_changes
所以,事件 1 是我最初创建审计规则时发生的,事件 2 发生在我执行ausearch
操作时。
我必须承认,第 4 行和第 5 行的事件有点神秘。当我调用usermod
命令时,都会创建这两个事件,并且它们都与我将 Vicky 和 Cleopatra 添加到secretcats
组的安全日志条目相关:
Dec 11 14:54:11 localhost sudo: donnie : TTY=pts/1 ; PWD=/home/donnie ; USER=root ; COMMAND=/sbin/usermod -a -G secretcats vicky
Dec 11 14:54:11 localhost usermod[14865]: add 'vicky' to group 'secretcats'
Dec 11 14:54:11 localhost usermod[14865]: add 'vicky' to shadow group 'secretcats'
Dec 11 14:54:25 localhost sudo: donnie : TTY=pts/1 ; PWD=/home/donnie ; USER=root ; COMMAND=/sbin/usermod -a -G secretcats cleopatra
Dec 11 14:54:25 localhost usermod[14871]: add 'cleopatra' to group 'secretcats'
Dec 11 14:54:25 localhost usermod[14871]: add 'cleopatra' to shadow group 'secretcats'
奇怪的是,将用户添加到辅助组不会修改passwd
文件。所以,我真的不知道为什么规则会触发创建第 4 行和第 5 行的事件。
这让我们留下了第 3 行的事件,那是我使用chfn
实际修改passwd
文件的地方。这是关于那个的secure
日志条目:
Dec 11 13:48:49 localhost sudo: donnie : TTY=pts/1 ; PWD=/etc ; USER=root ; COMMAND=/bin/chfn cleopatra
所以,在所有这些事件中,只有第 3 行的事件是实际修改了/etc/passwd
文件的。
我一直在这里提到的/var/log/secure
文件是在 Red Hat 类型的操作系统上,比如 CentOS。在你的 Ubuntu 机器上,你会看到/var/log/auth.log
文件。
搜索目录访问规则违规
在我们的下一个场景中,我们为 Vicky 和 Cleopatra 创建了一个共享目录,并为它创建了一个审计规则,看起来像这样:
sudo auditctl -w /secretcats/ -k secretcats_watch
因此,对这个目录的所有访问或尝试访问都应该触发警报。首先,让 Vicky 进入/secretcats
目录并运行ls -l
命令:
[vicky@localhost ~]$ cd /secretcats
[vicky@localhost secretcats]$ ls -l
total 4
-rw-rw-r--. 1 cleopatra secretcats 31 Dec 12 11:49 cleopatrafile.txt
[vicky@localhost secretcats]$
我们看到 Cleopatra 已经在那里并创建了一个文件。(我们稍后再回来讨论这个问题。)当事件触发 auditd 规则时,通常会在/var/log/audit/audit.log
文件中创建多条记录。如果你研究每个事件的每条记录,你会发现每条记录都涵盖了该事件的不同方面。当我执行ausearch
命令时,我看到了来自那个ls -l
操作的总共五条记录。为了节省空间,我只列出第一条和最后一条:
sudo ausearch -i -k secretcats_watch | less
type=PROCTITLE msg=audit(12/12/2017 12:15:35.447:14077) : proctitle=ls --color=auto -l
type=PATH msg=audit(12/12/2017 12:15:35.447:14077) : item=0 name=. inode=33583041 dev=fd:01 mode=dir,sgid,sticky,770 ouid=nobody ogid=secretcats rdev=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=NORMAL
type=CWD msg=audit(12/12/2017 12:15:35.447:14077) : cwd=/secretcats
type=SYSCALL msg=audit(12/12/2017 12:15:35.447:14077) : arch=x86_64 syscall=openat success=yes exit=3 a0=0xffffffffffffff9c a1=0x2300330 a2=O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC a3=0x0 items=1 ppid=10805 pid=10952 auid=vicky uid=vicky gid=vicky euid=vicky suid=vicky fsuid=vicky egid=vicky sgid=vicky fsgid=vicky tty=pts0 ses=1789 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
. . .
. . .
type=PROCTITLE msg=audit(12/12/2017 12:15:35.447:14081) : proctitle=ls --color=auto -l
type=PATH msg=audit(12/12/2017 12:15:35.447:14081) : item=0 name=cleopatrafile.txt inode=33583071 dev=fd:01 mode=file,664 ouid=cleopatra ogid=secretcats rdev=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=NORMAL
type=CWD msg=audit(12/12/2017 12:15:35.447:14081) : cwd=/secretcats
type=SYSCALL msg=audit(12/12/2017 12:15:35.447:14081) : arch=x86_64 syscall=getxattr success=no exit=ENODATA(No data available) a0=0x7fff7c266e60 a1=0x7f0a61cb9db0 a2=0x0 a3=0x0 items=1 ppid=10805 pid=10952 auid=vicky uid=vicky gid=vicky euid=vicky suid=vicky fsuid=vicky egid=vicky sgid=vicky fsgid=vicky tty=pts0 ses=1789 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
在这两条记录中,你可以看到所采取的行动(ls -l
),以及采取行动的人或者在这种情况下是猫的信息。由于这是一个 CentOS 机器,你还可以看到 SELinux 上下文信息。在第二条记录中,你还可以看到 Vicky 在执行ls
命令时看到的文件名。
接下来,让我们假设那个狡猾的查理登录并尝试进入/secretcats
目录:
[charlie@localhost ~]$ cd /secretcats
-bash: cd: /secretcats: Permission denied
[charlie@localhost ~]$ ls -l /secretcats
ls: cannot open directory /secretcats: Permission denied
[charlie@localhost ~]$
查理不是secretcats
组的成员,也没有权限进入secretcats
目录。因此,他应该触发一个警报消息。实际上,他触发了一个包含四条记录的警报,我再次只列出第一条和最后一条:
sudo ausearch -i -k secretcats_watch | less
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14152) : proctitle=ls --color=auto -l /secretcats
type=PATH msg=audit(12/12/2017 12:32:04.341:14152) : item=0 name=/secretcats inode=33583041 dev=fd:01 mode=dir,sgid,sticky,770 ouid=nobody ogid=secretcats rdev=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=NORMAL
type=CWD msg=audit(12/12/2017 12:32:04.341:14152) : cwd=/home/charlie
type=SYSCALL msg=audit(12/12/2017 12:32:04.341:14152) : arch=x86_64 syscall=lgetxattr success=yes exit=35 a0=0x7ffd8d18f7dd a1=0x7f2496858f8a a2=0x12bca30 a3=0xff items=1 ppid=11637 pid=11663 auid=charlie uid=charlie gid=charlie euid=charlie suid=charlie fsuid=charlie egid=charlie sgid=charlie fsgid=charlie tty=pts0 ses=1794 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
. . .
. . .
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14155) : proctitle=ls --color=auto -l /secretcats
type=PATH msg=audit(12/12/2017 12:32:04.341:14155) : item=0 name=/secretcats inode=33583041 dev=fd:01 mode=dir,sgid,sticky,770 ouid=nobody ogid=secretcats rdev=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=NORMAL
type=CWD msg=audit(12/12/2017 12:32:04.341:14155) : cwd=/home/charlie
type=SYSCALL msg=audit(12/12/2017 12:32:04.341:14155) : arch=x86_64 syscall=openat success=no exit=EACCES(Permission denied) a0=0xffffffffffffff9c a1=0x12be300 a2=O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC a3=0x0 items=1 ppid=11637 pid=11663 auid=charlie uid=charlie gid=charlie euid=charlie suid=charlie fsuid=charlie egid=charlie sgid=charlie fsgid=charlie tty=pts0 ses=1794 comm=ls exe=/usr/bin/ls subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
这里有两件事需要注意。首先,仅尝试cd
进入目录不会触发警报。然而,使用ls
尝试读取目录的内容会触发警报。其次,注意第二条记录中出现的Permission denied
消息。
我们将要查看的最后一组警报是在 Cleopatra 创建她的cleopatrafile.txt
文件时创建的。这个事件触发了一个包含 30 条记录的警报。以下是其中的两条:
. . .
. . .
type=PROCTITLE msg=audit(12/12/2017 11:49:37.536:13856) : proctitle=vim cleopatrafile.txt
type=PATH msg=audit(12/12/2017 11:49:37.536:13856) : item=0 name=. inode=33583041 dev=fd:01 mode=dir,sgid,sticky,770 ouid=nobody ogid=secretcats rdev=00:00 obj=unconfined_u:o
bject_r:default_t:s0 objtype=NORMAL
type=CWD msg=audit(12/12/2017 11:49:37.536:13856) : cwd=/secretcats
type=SYSCALL msg=audit(12/12/2017 11:49:37.536:13856) : arch=x86_64 syscall=open success=yes exit=4 a0=0x5ab983 a1=O_RDONLY a2=0x0 a3=0x63 items=1 ppid=9572 pid=9593 auid=cle
opatra uid=cleopatra gid=cleopatra euid=cleopatra suid=cleopatra fsuid=cleopatra egid=cleopatra sgid=cleopatra fsgid=cleopatra tty=pts0 ses=1779 comm=vim exe=/usr/bin/vim sub
j=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
----
type=PROCTITLE msg=audit(12/12/2017 11:49:56.001:13858) : proctitle=vim cleopatrafile.txt
type=PATH msg=audit(12/12/2017 11:49:56.001:13858) : item=1 name=/secretcats/.cleopatrafile.txt.swp inode=33583065 dev=fd:01 mode=file,600 ouid=cleopatra ogid=secretcats rdev
=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=DELETE
type=PATH msg=audit(12/12/2017 11:49:56.001:13858) : item=0 name=/secretcats/ inode=33583041 dev=fd:01 mode=dir,sgid,sticky,770 ouid=nobody ogid=secretcats rdev=00:00 obj=unc
onfined_u:object_r:default_t:s0 objtype=PARENT
type=CWD msg=audit(12/12/2017 11:49:56.001:13858) : cwd=/secretcats
type=SYSCALL msg=audit(12/12/2017 11:49:56.001:13858) : arch=x86_64 syscall=unlink success=yes exit=0 a0=0x15ee7a0 a1=0x1 a2=0x1 a3=0x7ffc2c82e6b0 items=2 ppid=9572 pid=9593
auid=cleopatra uid=cleopatra gid=cleopatra euid=cleopatra suid=cleopatra fsuid=cleopatra egid=cleopatra sgid=cleopatra fsgid=cleopatra tty=pts0 ses=1779 comm=vim exe=/usr/bin
/vim subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=secretcats_watch
. . .
. . .
你可以看出这两条消息中的第一条是 Cleopatra 保存文件并退出 vim 时发生的,因为第二条消息显示了objtype=DELETE
,她的临时 vim 交换文件被删除了。
好的,这都很好,但如果这些信息太多怎么办?如果你只想要一个快速而简洁的安全事件列表,那么我们将使用aureport
。我们将像之前一样使用它。
首先,让我们将aureport
的输出导入less
而不是grep
,这样我们就可以看到列标题:
[donnie@localhost ~]$ sudo aureport -i -k | less
Key Report
===============================================
# date time key success exe auid event
===============================================
1\. 12/11/2017 13:06:20 passwd_changes yes ? donnie 11393
2\. 12/11/2017 13:49:15 passwd_changes yes ? donnie 11511
3\. 12/11/2017 13:49:15 passwd_changes yes /usr/bin/chfn donnie 11512
4\. 12/11/2017 14:54:11 passwd_changes yes /usr/sbin/usermod donnie 11728
5\. 12/11/2017 14:54:25 passwd_changes yes /usr/sbin/usermod donnie 11736
. . .
. . .
success
列中的状态将是yes
或no
,取决于用户是否能够成功执行违反规则的操作。或者,如果事件不是触发规则的结果,它可能是一个问号。
对于查理,我们在第 48 行看到了一个yes
事件,而在第 49 到 51 行的事件中都有一个no
状态。我们还看到所有这些条目都是由查理使用ls
命令触发的:
sudo aureport -i -k | grep 'secretcats_watch'
[donnie@localhost ~]$ sudo aureport -i -k | grep 'secretcats_watch'
6\. 12/11/2017 15:01:25 secretcats_watch yes ? donnie 11772
8\. 12/12/2017 11:49:29 secretcats_watch yes /usr/bin/ls cleopatra 13828
9\. 12/12/2017 11:49:37 secretcats_watch yes /usr/bin/vim cleopatra 13830
10\. 12/12/2017 11:49:37 secretcats_watch yes /usr/bin/vim cleopatra 13829
. . .
. . .
48\. 12/12/2017 12:32:04 secretcats_watch yes /usr/bin/ls charlie 14152
49\. 12/12/2017 12:32:04 secretcats_watch no /usr/bin/ls charlie 14153
50\. 12/12/2017 12:32:04 secretcats_watch no /usr/bin/ls charlie 14154
51\. 12/12/2017 12:32:04 secretcats_watch no /usr/bin/ls charlie 14155
[donnie@localhost ~]$
你可能会认为第 48 行的yes
事件表明查理成功读取了secretcats
目录的内容。要进一步分析,请查看每行末尾的事件编号,并将其与我们之前的ausearch
命令的输出进行对照。你会发现事件编号 14152 到 14155 属于具有相同时间戳的记录。我们可以在每条记录的第一行看到这一点:
[donnie@localhost ~]$ sudo ausearch -i -k secretcats_watch | less
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14152) : proctitle=ls --color=auto -l /secretcats
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14153) : proctitle=ls --color=auto -l /secretcats
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14154) : proctitle=ls --color=auto -l /secretcats
type=PROCTITLE msg=audit(12/12/2017 12:32:04.341:14155) : proctitle=ls --color=auto -l /secretcats
正如我们之前指出的,这个系列的最后一条记录显示了查理的Permission denied
,这才是真正重要的。
空间不允许我对审计日志记录中的每个项目进行全面解释。但是,您可以在官方的 Red Hat 文档中阅读有关此处的内容:access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-understanding_audit_log_files
。
搜索系统调用规则违规
我们创建的第三条规则是监视这个狡猾的查尔斯。这条规则将在查尔斯尝试打开或创建文件时向我们发出警报。(正如我们之前指出的,1006
是查尔斯的用户 ID 号。)
sudo auditctl -a always,exit -F arch=b64 -S openat -F auid=1006
尽管查尔斯在这个系统上并没有做太多事情,但这条规则给我们带来了比我们预期的更多的日志条目。我们只看其中的一些条目:
time->Tue Dec 12 11:49:29 2017
type=PROCTITLE msg=audit(1513097369.952:13828): proctitle=6C73002D2D636F6C6F723D6175746F
type=PATH msg=audit(1513097369.952:13828): item=0 name="." inode=33583041 dev=fd:01 mode=043770 ouid=99 ogid=1009 rdev=00:00 obj=unconfined_u:object_r:default_t:s0 objtype=NO
RMAL
type=CWD msg=audit(1513097369.952:13828): cwd="/secretcats"
type=SYSCALL msg=audit(1513097369.952:13828): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=10d1560 a2=90800 a3=0 items=1 ppid=9572 pid=9592 auid=1004 u
id=1004 gid=1006 euid=1004 suid=1004 fsuid=1004 egid=1006 sgid=1006 fsgid=1006 tty=pts0 ses=1779 comm="ls" exe="/usr/bin/ls" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0
:c0.c1023 key="secretcats_watch"
这条记录是在查尔斯试图访问/secretcats/
目录时生成的。所以,我们可以期待看到这个。但是,我们没有预料到的是查尔斯通过安全外壳登录系统时间接访问的文件记录的数量之多。这里只是其中的一部分:
time->Tue Dec 12 11:50:28 2017
type=PROCTITLE msg=audit(1513097428.662:13898): proctitle=737368643A20636861726C6965407074732F30
type=PATH msg=audit(1513097428.662:13898): item=0 name="/proc/9726/fd" inode=1308504 dev=00:03 mode=040500 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:unconfined_r:unconfined_t
:s0-s0:c0.c1023 objtype=NORMAL
type=CWD msg=audit(1513097428.662:13898): cwd="/home/charlie"
type=SYSCALL msg=audit(1513097428.662:13898): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=7ffc7ca1d840 a2=90800 a3=0 items=1 ppid=9725 pid=9726 auid=1
006 uid=1006 gid=1008 euid=1006 suid=1006 fsuid=1006 egid=1008 sgid=1008 fsgid=1008 tty=pts0 ses=1781 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined_u:unconfined_r:unconfin
ed_t:s0-s0:c0.c1023 key=(null)
----
time->Tue Dec 12 11:50:28 2017
type=PROCTITLE msg=audit(1513097428.713:13900): proctitle=737368643A20636861726C6965407074732F30
type=PATH msg=audit(1513097428.713:13900): item=0 name="/etc/profile.d/" inode=33593031 dev=fd:01 mode=040755 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:bin_t:s0 objtype=
NORMAL
type=CWD msg=audit(1513097428.713:13900): cwd="/home/charlie"
type=SYSCALL msg=audit(1513097428.713:13900): arch=c000003e syscall=257 success=yes exit=3 a0=ffffffffffffff9c a1=1b27930 a2=90800 a3=0 items=1 ppid=9725 pid=9726 auid=1006 u
id=1006 gid=1008 euid=1006 suid=1006 fsuid=1006 egid=1008 sgid=1008 fsgid=1008 tty=pts0 ses=1781 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s
0-s0:c0.c1023 key=(null)
在第一条记录中,我们看到查尔斯访问了/usr/sbin/sshd
文件。在第二条记录中,我们看到他访问了/usr/bin/bash
文件。并不是查尔斯选择访问这些文件。操作系统在正常的登录事件中为他访问了这些文件。因此,正如您所看到的,当您创建审计规则时,您必须小心您的愿望,因为有明显的危险,愿望可能会实现。如果您真的需要监视某人,您将需要创建一个不会给您太多信息的规则。
在此期间,我们也可以看看aureport
的输出是什么样的:
[donnie@localhost ~]$ sudo aureport -s -i | grep 'openat'
[sudo] password for donnie:
1068\. 12/12/2017 11:49:29 openat 9592 ls cleopatra 13828
1099\. 12/12/2017 11:50:28 openat 9665 sshd charlie 13887
1100\. 12/12/2017 11:50:28 openat 9665 sshd charlie 13889
1101\. 12/12/2017 11:50:28 openat 9665 sshd charlie 13890
1102\. 12/12/2017 11:50:28 openat 9726 sshd charlie 13898
1103\. 12/12/2017 11:50:28 openat 9726 bash charlie 13900
1104\. 12/12/2017 11:50:28 openat 9736 grep charlie 13901
1105\. 12/12/2017 11:50:28 openat 9742 grep charlie 13902
1108\. 12/12/2017 11:50:51 openat 9766 ls charlie 13906
1110\. 12/12/2017 12:15:35 openat 10952 ls vicky 14077
1115\. 12/12/2017 12:30:54 openat 11632 sshd charlie 14129
1116\. 12/12/2017 12:30:54 openat 11632 sshd charlie 14131
1117\. 12/12/2017 12:30:54 openat 11632 sshd charlie 14132
1118\. 12/12/2017 12:30:54 openat 11637 sshd charlie 14140
1119\. 12/12/2017 12:30:54 openat 11637 bash charlie 14142
1120\. 12/12/2017 12:30:54 openat 11647 grep charlie 14143
1121\. 12/12/2017 12:30:54 openat 11653 grep charlie 14144
1125\. 12/12/2017 12:32:04 openat 11663 ls charlie 14155
[donnie@localhost ~]$
除了查尔斯所做的事情,我们还可以看到维基和克利奥帕特拉所做的事情。这是因为我们为/secretcats/
目录设置的规则在维基和克利奥帕特拉访问、查看或创建该目录中的文件时生成了openat
事件。
生成认证报告
您可以生成用户认证报告,而无需定义任何审计规则。只需使用aureport
加上-au
选项开关即可。(记住au
,认证的前两个字母。)
[donnie@localhost ~]$ sudo aureport -au
[sudo] password for donnie:
Authentication Report
============================================
# date time acct host term exe success event
============================================
1\. 10/28/2017 13:38:52 donnie localhost.localdomain tty1 /usr/bin/login yes 94
2\. 10/28/2017 13:39:03 donnie localhost.localdomain /dev/tty1 /usr/bin/sudo yes 102
3\. 10/28/2017 14:04:51 donnie localhost.localdomain /dev/tty1 /usr/bin/sudo yes 147
. . .
. . .
239\. 12/12/2017 11:50:20 charlie 192.168.0.222 ssh /usr/sbin/sshd no 13880
244\. 12/12/2017 12:10:06 cleopatra 192.168.0.222 ssh /usr/sbin/sshd no 13992
247\. 12/12/2017 12:14:28 vicky 192.168.0.222 ssh /usr/sbin/sshd no 14049
250\. 12/12/2017 12:30:49 charlie 192.168.0.222 ssh /usr/sbin/sshd no 14122
265\. 12/12/2017 19:06:20 charlie 192.168.0.222 ssh /usr/sbin/sshd no 725
269\. 12/12/2017 19:23:45 donnie ? /dev/pts/0 /usr/bin/sudo no 779
[donnie@localhost ~]$
对于登录事件,这告诉我们用户是在本地终端登录还是通过安全外壳远程登录。要查看任何事件的详细信息,请使用ausearch
加上-a
选项,然后跟上您在行末看到的事件编号。(奇怪的是,-a
选项代表一个事件。)让我们看看查尔斯的事件编号 14122:
[donnie@localhost ~]$ sudo ausearch -a 14122
----
time->Tue Dec 12 12:30:49 2017
type=USER_AUTH msg=audit(1513099849.322:14122): pid=11632 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:sshd_t:s0-s0:c0.c1023 msg='op=pubkey acct="charlie" exe="/usr/sbin/sshd" hostname=? addr=192.168.0.222 terminal=ssh res=failed'
问题在于这真的毫无意义。我是为查尔斯做的登录记录,我可以确定查尔斯从未有过任何登录失败。事实上,我们可以将其与/var/log/secure
文件中的匹配条目进行关联:
Dec 12 12:30:53 localhost sshd[11632]: Accepted password for charlie from 192.168.0.222 port 34980 ssh2
Dec 12 12:30:54 localhost sshd[11632]: pam_unix(sshd:session): session opened for user charlie by (uid=0)
这两个条目的时间戳比ausearch
输出的时间戳晚了几秒,但没关系。这个日志文件中没有任何迹象表明查尔斯曾经有过登录失败,这两个条目清楚地显示了查尔斯的登录确实成功了。这里的教训是,当您在ausearch
或aureport
输出中看到一些奇怪的东西时,一定要将其与适当的认证日志文件中的匹配条目进行关联,以更好地了解发生了什么。(通过认证日志文件,我指的是 Red Hat 类型系统的/var/log/secure
和 Ubuntu 系统的/var/log/auth.log
。其他 Linux 发行版的名称可能有所不同。)
使用预定义的规则集
在你的 CentOS 机器的/usr/share/doc/audit-version_number/
目录中,你会看到一些预先制定的不同场景的规则集。一旦你在 Ubuntu 上安装了 auditd,你也会有适用于它的审计规则,但对于 Ubuntu 16.04 和 Ubuntu 17.10,位置是不同的。在 Ubuntu 16.04 上,规则位于/usr/share/doc/auditd/examples/
目录中。在 Ubuntu 17.10 上,它们位于/usr/share/doc/auditd/examples/rules/
目录中。无论如何,这三个发行版中有一些规则集是共通的。让我们看看 CentOS 机器上有什么:
[donnie@localhost rules]$ pwd
/usr/share/doc/audit-2.7.6/rules
[donnie@localhost rules]$ ls -l
total 96
-rw-r--r--. 1 root root 163 Aug 4 17:29 10-base-config.rules
-rw-r--r--. 1 root root 284 Apr 19 2017 10-no-audit.rules
-rw-r--r--. 1 root root 93 Apr 19 2017 11-loginuid.rules
-rw-r--r--. 1 root root 329 Apr 19 2017 12-cont-fail.rules
-rw-r--r--. 1 root root 323 Apr 19 2017 12-ignore-error.rules
-rw-r--r--. 1 root root 516 Apr 19 2017 20-dont-audit.rules
-rw-r--r--. 1 root root 273 Apr 19 2017 21-no32bit.rules
-rw-r--r--. 1 root root 252 Apr 19 2017 22-ignore-chrony.rules
-rw-r--r--. 1 root root 4915 Apr 19 2017 30-nispom.rules
-rw-r--r--. 1 root root 5952 Apr 19 2017 30-pci-dss-v31.rules
-rw-r--r--. 1 root root 6663 Apr 19 2017 30-stig.rules
-rw-r--r--. 1 root root 1498 Apr 19 2017 31-privileged.rules
-rw-r--r--. 1 root root 218 Apr 19 2017 32-power-abuse.rules
-rw-r--r--. 1 root root 156 Apr 19 2017 40-local.rules
-rw-r--r--. 1 root root 439 Apr 19 2017 41-containers.rules
-rw-r--r--. 1 root root 672 Apr 19 2017 42-injection.rules
-rw-r--r--. 1 root root 424 Apr 19 2017 43-module-load.rules
-rw-r--r--. 1 root root 326 Apr 19 2017 70-einval.rules
-rw-r--r--. 1 root root 151 Apr 19 2017 71-networking.rules
-rw-r--r--. 1 root root 86 Apr 19 2017 99-finalize.rules
-rw-r--r--. 1 root root 1202 Apr 19 2017 README-rules
[donnie@localhost rules]$
我想重点关注的三个文件是nispom
、pci-dss
和stig
文件。这三个规则集分别设计用于满足特定认证机构的审计标准。依次来看,这些规则集是:
-
nispom
:国家工业安全计划——你会看到这个规则集在美国国防部或其承包商处使用 -
pci-dss
:支付卡行业数据安全标准——如果你在银行或金融行业工作,或者你只是经营一个接受信用卡的在线业务,你可能会对这个非常熟悉 -
stig
:安全技术实施指南——如果你在美国政府工作,或者可能是其他政府,你将会处理这个
要使用这些规则集中的一个,将相应的文件复制到/etc/audit/rules.d/
目录中:
[donnie@localhost rules]$ sudo cp 30-pci-dss-v31.rules /etc/audit/rules.d
[donnie@localhost rules]$
然后,重新启动 auditd 守护程序以读取新规则。
对于 Red Hat 或 CentOS:
sudo service auditd restart
对于 Ubuntu:
sudo systemctl restart auditd
当然,总会有可能某个规则集中的特定规则对你不起作用,或者你可能需要启用当前禁用的规则。如果是这样,只需在文本编辑器中打开规则文件,注释掉不起作用的部分,或取消注释你需要启用的部分。
尽管 auditd 非常酷,但请记住它只会警告你可能存在的安全漏洞。它不会采取任何措施来加固系统。
这基本上就是我们对 auditd 系统的讨论。试一试,看看你的想法如何。
使用 oscap 应用 OpenSCAP 策略
SCAP,即安全内容自动化协议(SCAP),是由美国国家标准与技术研究所创建的。它包括用于设置安全系统的加固指南、加固模板和基线配置指南。OpenSCAP 是一套免费开源软件工具,可用于实施 SCAP。它包括以下内容:
-
可以应用于系统的安全配置文件。有不同的配置文件,满足几个不同认证机构的要求。
-
安全指南,帮助你进行系统的初始设置。
-
oscap
命令行实用程序用于应用安全模板。 -
在具有桌面界面的 Red Hat 类型系统上,你可以使用 SCAP Workbench,这是一种图形界面实用程序。
你可以在 Red Hat 或 Ubuntu 发行版上安装 OpenSCAP,但在 Red Hat 发行版上实现得更好。首先,Red Hat 世界拥有非常酷的 SCAP Workbench,而 Ubuntu 世界没有。当你安装 Red Hat 类型的操作系统时,可以选择在安装过程中应用 SCAP 配置文件。在 Ubuntu 上无法这样做。最后,Red Hat 发行版配备了一套相当完整的可供使用的配置文件。耐人寻味的是,Ubuntu 只配备了用于较旧版本的 Fedora 和 Red Hat 的配置文件,这些配置文件在 Ubuntu 系统上无法使用。如果你想要 Ubuntu 可用的配置文件,你需要从 OpenSCAP 网站下载并手动安装它们。(我们将在本章的最后一节中介绍这一点。)话虽如此,让我们看看如何安装 OpenSCAP 以及如何使用两种发行版都通用的命令行实用程序。由于 CentOS 具有更完整的实现,我将在演示中使用它。
安装 OpenSCAP
在你的 CentOS 机器上,假设你在操作系统安装过程中没有安装 OpenSCAP,按照以下步骤进行:
sudo yum install openscap-scanner scap-security-guide
在 Ubuntu 机器上,执行以下操作:
sudo apt install python-openscap
查看配置文件
在 CentOS 机器上,你会在/usr/share/xml/scap/ssg/content/
目录中看到配置文件。在 Ubuntu 机器上,你会在/usr/share/openscap/
目录中看到少量的配置文件。配置文件是.xml
格式的,每个文件包含一个或多个可以应用到系统上的配置文件:
[donnie@localhost content]$ pwd
/usr/share/xml/scap/ssg/content
[donnie@localhost content]$ ls -l
total 50596
-rw-r--r--. 1 root root 6734643 Oct 19 19:40 ssg-centos6-ds.xml
-rw-r--r--. 1 root root 1596043 Oct 19 19:40 ssg-centos6-xccdf.xml
-rw-r--r--. 1 root root 11839886 Oct 19 19:41 ssg-centos7-ds.xml
-rw-r--r--. 1 root root 2636971 Oct 19 19:40 ssg-centos7-xccdf.xml
-rw-r--r--. 1 root root 642 Oct 19 19:40 ssg-firefox-cpe-dictionary.xml
. . .
. . .
-rw-r--r--. 1 root root 11961196 Oct 19 19:41 ssg-rhel7-ds.xml
-rw-r--r--. 1 root root 851069 Oct 19 19:40 ssg-rhel7-ocil.xml
-rw-r--r--. 1 root root 2096046 Oct 19 19:40 ssg-rhel7-oval.xml
-rw-r--r--. 1 root root 2863621 Oct 19 19:40 ssg-rhel7-xccdf.xml
[donnie@localhost content]$
用于处理 OpenSCAP 的命令行实用程序是oscap
。我们可以使用info
开关来查看任何配置文件的信息。让我们看看ssg-centos7-xccdf.xml
文件:
[donnie@localhost content]$ sudo oscap info ssg-centos7-xccdf.xml
Document type: XCCDF Checklist
Checklist version: 1.1
Imported: 2017-10-19T19:40:43
Status: draft
Generated: 2017-10-19
Resolved: true
Profiles:
standard
pci-dss
C2S
rht-ccp
common
stig-rhel7-disa
stig-rhevh-upstream
ospp-rhel7
cjis-rhel7-server
docker-host
nist-800-171-cui
Referenced check files:
ssg-rhel7-oval.xml
system: http://oval.mitre.org/XMLSchema/oval-definitions-5
ssg-rhel7-ocil.xml
system: http://scap.nist.gov/schema/ocil/2
https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL7.xml.bz2
system: http://oval.mitre.org/XMLSchema/oval-definitions-5
[donnie@localhost content]$
我们可以看到这个文件包含了 11 个不同的配置文件,我们可以应用到系统上。其中,你可以看到stig
和pci-dss
的配置文件,就像我们为审计规则所做的那样。而且,如果你正在运行 Docker 容器,docker-host
配置文件将非常方便。
扫描系统
现在,假设我们需要确保我们的系统符合支付卡行业标准。我们首先要扫描 CentOS 机器,看看需要什么样的补救措施。(请注意,以下命令非常长,在打印页面上换行了。)
sudo oscap xccdf eval --profile pci-dss --results scan-xccdf-results.xml /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml
正如我们一直喜欢做的那样,让我们来分解一下:
-
xccdf eval
:可扩展配置清单描述是我们可以编写安全配置规则的语言之一。我们将使用这种语言编写的配置文件来对系统进行评估。 -
--profile pci-dss
:在这里,我指定我要使用支付卡行业数据安全标准配置文件来评估系统。 -
--results scan-xccdf-results.xml
:我将把扫描结果保存到这个.xml
格式的文件中。扫描完成后,我将从这个文件中创建报告。 -
/usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml
:这个文件包含了pci-dss
配置文件。
随着扫描的进行,输出将发送到屏幕以及指定的输出文件。这是一个很长的列表,所以我只会给你展示其中的一些:
Ensure Red Hat GPG Key Installed
ensure_redhat_gpgkey_installed
pass
Ensure gpgcheck Enabled In Main Yum Configuration
ensure_gpgcheck_globally_activated
pass
Ensure gpgcheck Enabled For All Yum Package Repositories
ensure_gpgcheck_never_disabled
pass
Ensure Software Patches Installed
security_patches_up_to_date
notchecked
. . .
. . .
Install AIDE
package_aide_installed
fail
Build and Test AIDE Database
aide_build_database
fail
. . .
. . .
所以,我们安装了 GPG 加密,这很好。但是,我们没有安装 AIDE 入侵检测系统,这是一个坏事。
现在我已经运行了扫描并创建了一个包含结果的输出文件,我可以制作我的报告了:
sudo oscap xccdf generate report scan-xccdf-results.xml > scan-xccdf-results.html
这会从.xml
格式文件中提取信息,这些文件不是为人类阅读而设计的,并将其转移到一个.html
文件中,你可以在 Web 浏览器中打开。(记录上,报告显示有 20 个问题需要解决。)
系统的补救措施
所以,我们有 20 个问题需要解决,才能使我们的系统符合支付卡行业标准。让我们看看oscap
能为我们解决多少个问题:
sudo oscap xccdf eval --remediate --profile pci-dss --results scan-xccdf-remediate-results.xml /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml
这是我用来执行初始扫描的相同命令,只是我添加了--remediate
选项,并将结果保存到不同的文件中。当你运行这个命令时,你需要有点耐心,因为修复一些问题涉及下载和安装软件包。事实上,就在我打字的时候,oscap
正在忙着下载和安装缺失的 AIDE 入侵检测系统包。
好的,补救措施仍在进行中,但我仍然可以向你展示一些已经修复的问题:
Disable Prelinking
disable_prelink
error
Install AIDE
package_aide_installed
fixed
Build and Test AIDE Database
aide_build_database
fixed
Configure Periodic Execution of AIDE
aide_periodic_cron_checking
fixed
Verify and Correct File Permissions with RPM
rpm_verify_permissions
error
Prevent Log In to Accounts With Empty Password
no_empty_passwords
fixed
. . .
. . .
由于oscap
无法修复的一些问题,会出现一些错误,但这是正常的。至少你知道了这些问题,这样你就可以尝试自己修复它们。
还有,看看这个。你还记得在第二章中,保护用户账户,我让你跳过一些步骤,以确保用户拥有定期过期的强密码吗?通过应用这个 OpenSCAP 配置文件,所有这些问题都会自动解决:
Set Password Maximum Age
accounts_maximum_age_login_defs
fixed
Set Account Expiration Following Inactivity
account_disable_post_pw_expiration
fixed
Set Password Strength Minimum Digit Characters
accounts_password_pam_dcredit
fixed
Set Password Minimum Length
accounts_password_pam_minlen
fixed
Set Password Strength Minimum Uppercase Characters
accounts_password_pam_ucredit
fixed
Set Password Strength Minimum Lowercase Characters
accounts_password_pam_lcredit
fixed
Set Deny For Failed Password Attempts
accounts_passwords_pam_faillock_deny
fixed
Set Lockout Time For Failed Password Attempts
accounts_passwords_pam_faillock_unlock_time
fixed
Limit Password Reuse
accounts_password_pam_unix_remember
fixed
所以,OpenSCAP 非常酷,即使命令行工具也不难使用。
使用 SCAP Workbench
对于安装了桌面环境的 Red Hat 和 CentOS 机器,我们有 SCAP Workbench。然而,如果你上次使用 SCAP Workbench 是在 Red Hat/CentOS 7.0 或 Red Hat/CentOS 7.1 上,你可能会感到非常失望。事实上,早期版本的 Workbench 是如此糟糕,以至于根本无法使用。幸运的是,随着 Red Hat 7.2 和 CentOS 7.2 的推出,情况得到了很大改善。现在,Workbench 是一个非常好用的小工具。
要在你的 CentOS 机器上安装它,只需使用以下代码:
sudo yum install scap-workbench
是的,包名只是scap-workbench
,而不是openscap-workbench
。我不知道为什么,但我知道如果你搜索openscap
包,你永远也找不到它。
安装完成后,你会在“系统工具”菜单下看到它的菜单项。
当你第一次打开程序时,你可能会认为系统会要求你输入 root 或 sudo 密码。但是,它没有。我们马上就会看到这是否会影响我们。
在打开屏幕上你会看到一个下拉列表,让你选择要加载的内容类型。我会选择 CentOS7,然后点击“加载内容”按钮:
接下来,你会在顶部面板看到可以选择所需配置文件的地方。你还可以选择自定义配置文件,以及是否要在本地机器上或远程机器上运行扫描。在底部面板上,你会看到该配置文件的规则列表。你可以展开每个规则项以获取该规则的描述:
现在,让我们点击“扫描”按钮看看会发生什么:
很好。正如我所希望的那样,它会提示你输入 sudo 密码。除此之外,我会让你自己去尝试。这只是另一个 GUI 工具,所以剩下的应该很容易弄清楚。
关于 OpenSCAP 配置文件的更多信息
所以现在你可能会说,“好吧,这都很好,但我怎么找出这些配置文件中有什么,我需要哪一个呢?”好吧,有几种方法。
第一种方法,我刚刚向你展示的,是在安装了桌面界面的机器上安装 SCAP Workbench,并阅读每个配置文件的所有规则的描述。
第二种方法可能更容易一些,就是去 OpenSCAP 网站查看他们那里的文档。
你可以在www.open-scap.org/security-policies/choosing-policy/
找到有关可用 OpenSCAP 配置文件的信息。
就选择哪个配置文件而言,有几件事情需要考虑:
-
如果你在金融领域工作,或者在从事在线金融交易的企业工作,那么选择
pci-dss
配置文件。 -
如果你在政府机构工作,尤其是美国政府,那么根据特定机构的要求,选择
stig
配置文件或nispom
配置文件。 -
如果这两种情况都不适用于你的情况,那么你只需要进行一些研究和规划,以找出真正需要被锁定的内容。浏览每个配置文件中的规则,并阅读 OpenSCAP 网站上的文档,以帮助决定你需要什么。
你接下来会想,“那 Ubuntu 呢?我们已经知道 Ubuntu 附带的配置文件是无用的,因为它们是为 RHEL 和 Fedora 设计的。”这是真的,但你会在 OpenSCAP 网站上找到各种不同发行版的配置文件,包括 Ubuntu 的长期支持版本:
在系统安装过程中应用 OpenSCAP 配置文件
我喜欢 Red Hat 的人的一点是,他们完全懂得这个安全问题。是的,我们可以锁定其他发行版并使它们更安全,就像我们已经看到的那样。但是,对于 Red Hat 发行版来说,这要容易一些。对于很多事情,Red Hat 类型的发行版的维护者已经设置了安全的默认选项,而其他发行版上并没有被安全设置。(例如,Red Hat 发行版是唯一默认锁定用户家目录的发行版。)对于其他事情,Red Hat 类型的发行版提供了工具和安装选项,帮助那些忙碌、注重安全的管理员更轻松地工作。
当你安装 Red Hat 7 类型的发行版时,在操作系统安装过程中,你将有机会应用 OpenSCAP 配置文件。在这个 CentOS 7 安装程序屏幕上,你可以在右下角看到选择安全配置文件的选项:
你所需要做的就是点击那个,然后选择你的配置文件:
好的,我们关于 OpenSCAP 的讨论基本上就到这里了。唯一剩下的要补充的是,尽管 OpenSCAP 很棒,但它并不能做到一切。例如,一些安全标准要求你必须有特定的目录,比如/home/
或/var/
,在它们自己独立的分区上。OpenSCAP 扫描会提醒你如果情况不是这样,但它不能改变你现有的分区方案。所以对于这样的事情,你需要从规定你安全要求的管理机构那里得到一个清单,并在甚至触及 OpenSCAP 之前做一些高级工作。
摘要
在本章中,我们涵盖了很多内容,看到了一些非常酷的东西。我们首先看了一些防病毒扫描器,这样我们就可以防止任何访问我们的 Linux 服务器的 Windows 机器感染。在 Rootkit Hunter 部分,我们看到了如何扫描这些讨厌的 rootkit。了解如何审计系统非常重要,特别是在高安全环境中,我们看到了如何做到这一点。最后,我们讨论了如何使用 OpenSCAP 加固我们的系统。
在下一章中,我们将看一下漏洞扫描和入侵检测。到时候见。
第九章:漏洞扫描和入侵检测
有很多威胁存在,其中一些甚至可能渗入您的网络。您会想知道发生了什么,因此您需要一个良好的网络入侵检测系统(NIDS)。我们将看看 Snort,这可能是最著名的一个。然后我会向您展示一种快速设置 Snort 系统的方法。
我们已经看到了如何通过在要扫描的机器上安装扫描工具来扫描病毒和 rootkit。但是,还有很多漏洞可以进行扫描,我会向您展示一些很酷的工具可以用于此。
本章涵盖以下主题:
-
介绍 Snort 和 Security Onion
-
使用 Lynis 进行扫描和加固
-
使用 OpenVAS 查找漏洞
-
使用 Nikto 进行 Web 服务器扫描
查看 Snort 和 Security Onion
Snort 是一个 NIDS,是作为免费开源软件产品提供的。程序本身是免费的,但如果您想拥有完整的、最新的威胁检测规则集,就需要付费。Snort 最初是一个单人项目,但现在由思科公司拥有。但要明白,这不是您要保护的机器上安装的东西。相反,您至少需要一个专用的 Snort 机器在网络的某个地方,只是监视所有网络流量,观察异常情况。当它看到不应该出现的流量时——例如表明存在机器人的流量——它可以向管理员发送警报消息,甚至可以根据规则的配置阻止异常流量。对于小型网络,您可以只有一个 Snort 机器,既作为控制台又作为传感器。对于大型网络,您可以设置一个 Snort 机器作为控制台,并让它接收其他作为传感器设置的 Snort 机器的报告。
Snort 并不难处理,但是从头开始设置完整的 Snort 解决方案可能有点繁琐。在我们了解了 Snort 的基本用法之后,我将向您展示如何通过设置预构建的 Snort 设备大大简化事情。
空间不允许我提供有关 Snort 的全面教程。相反,我将提供一个高层次的概述,然后向您提供其他学习 Snort 的资源。
获取和安装 Snort
Snort 不在任何 Linux 发行版的官方软件库中,因此您需要从 Snort 网站获取。在他们的下载页面上,您将看到 Fedora 和 CentOS 的.rpm
格式的安装程序文件,以及 Windows 的.exe
安装程序文件。但是,您在 Ubuntu 上看不到任何.deb
安装程序文件。没关系,因为他们还提供源代码文件,您可以在各种不同的 Linux 发行版上编译。为了简化事情,让我们只谈谈在 CentOS 7 上安装 Snort 与预构建的.rpm
软件包。
您可以从官方 Snort 网站获取 Snort 和 Snort 培训:www.snort.org
。
在 Snort 主页上,只需向下滚动一点,你就会看到如何下载和安装 Snort 的指南。点击 Centos 选项卡并按照步骤操作。第 1 步中的命令将下载并安装 Snort,如下面的屏幕截图所示:
第 2 步和第 3 步涉及注册 Oinkcode,以便您可以下载官方的 Snort 检测规则,然后安装 PulledPork,以便您可以自动更新规则,如下面的屏幕截图所示:
请记住,Snort 提供的免费检测规则大约比付费订阅者获得的规则晚一个月。但是,就学习目的而言,它们就是您所需要的一切。此外,如果您选择不获取 Oinkcode,您可以使用社区规则,这是官方 Snort 规则的一个子集。
第 4 步只是阅读文档:
就是这样。您现在拥有一个可用的 Snort 副本。唯一的问题是,到目前为止,您只有命令行界面,这可能不是您想要的。
Snort 的图形界面
普通的、未装饰的 Snort 将做您需要它做的事情,并将其发现保存到其自己的一组日志文件中。但是,阅读日志文件以辨别网络流量趋势可能会有点乏味,因此您需要一些工具来帮助您。最好的工具是图形工具,它们可以为您提供对网络情况的良好可视化。
一个例子是基本分析和安全引擎(BASE),如下截图所示:
还有几个,但我会在我们到达* Security Onion *部分时向您展示它们。
您可以从作者的* Professionally Evil *网站了解有关 BASE 的更多信息:professionallyevil.com/
获取预构建的 Snort 设备
设置 Snort 本身并不是太难。但是,如果您一切都是手动操作,那么在设置控制台、传感器和您选择的图形前端之后,可能会有点乏味。因此——想象一下,当我戴着墨镜凝视着您说这些话时——如果我告诉您,您可以将 Snort 设置为即插即用设备的一部分呢?如果我告诉您,设置这样的设备绝对是轻而易举的呢?我想您可能会说,“那就给我看看吧!”
如果您因使 Snort 部署变得如此简单而感到内疚,那么实际上没有必要。一位 Snort 官方代表曾经告诉我,大多数人都以这种方式部署 Snort。
由于 Snort 是一个自由开源软件(FOSS)项目,因此人们将其构建到自己的 FOSS 应用程序中是完全合法的。此外,如果您回想一下我们在第三章中对防火墙的讨论,使用防火墙保护服务器,我完全忽略了创建网络地址转换(NAT)规则的讨论,这是您设置边缘或网关类型防火墙所需的。这是因为有几个 Linux 发行版专门为此目的而创建。如果我告诉您,其中一些还包括 Snort 的完整实现呢?
IPFire 完全免费,只需几分钟即可设置。您可以将其安装在至少具有两个网络接口适配器的计算机上,并将其配置为与您的网络配置相匹配。这是一种代理类型的防火墙,这意味着除了进行正常的防火墙类型的数据包检查外,它还包括缓存、内容过滤和 NAT 功能。您可以以多种不同的配置设置 IPFire:
-
在具有两个网络接口适配器的计算机上,您可以将一个连接到互联网,另一个连接到内部局域网。
-
使用三个网络适配器,您可以将一个连接到互联网,一个连接到内部局域网,一个连接到非军事区(DMZ),在那里您有面向互联网的服务器。
-
通过第四个网络适配器,您可以拥有上述所有内容,以及对无线网络的保护。
安装 IPFire 后,您需要使用普通工作站的 Web 浏览器导航到 IPFire 仪表板。在 Services 菜单下,您会看到入侵检测的条目。单击该条目即可进入此屏幕,您可以在此屏幕上下载并启用 Snort 检测规则:
实际上,您可能只需要从命令行进行一点微调。也就是说,您可能需要进入规则目录,并确保您要启用的规则已启用。在我的演示机器上,我安装了社区规则和新兴威胁规则:
[root@ipfire rules]# ls -l
total 19336
-rw-r--r-- 1 nobody nobody 1656 Dec 19 06:01 BSD-License.txt
-rw-r--r-- 1 nobody nobody 2638 Dec 19 06:01 classification.config
-rw-r--r-- 1 nobody nobody 1478085 Dec 19 06:01 community.rules
-rw-r--r-- 1 nobody nobody 15700 Dec 19 06:01 compromised-ips.txt
-rw-r--r-- 1 nobody nobody 378690 Dec 19 06:01 emerging-activex.rules
-rw-r--r-- 1 nobody nobody 79832 Dec 19 06:01 emerging-attack_response.rules
-rw-r--r-- 1 nobody nobody 82862 Dec 19 06:01 emerging-botcc.portgrouped.rules
-rw-r--r-- 1 nobody nobody 249176 Dec 19 06:01 emerging-botcc.rules
-rw-r--r-- 1 nobody nobody 34658 Dec 19 06:01 emerging-chat.rules
. . .
. . .
-rw-r--r-- 1 nobody nobody 1375 Dec 19 06:01 reference.config
-rw-r--r-- 1 nobody nobody 3691529 Dec 19 06:01 sid-msg.map
-rw-r--r-- 1 nobody nobody 0 Dec 19 06:01 snort-2.9.0-enhanced-open.txt
-rw-r--r-- 1 nobody nobody 53709 Dec 19 06:01 unicode.map
-rw-r--r-- 1 nobody nobody 21078 Dec 19 04:46 VRT-License.txt
[root@ipfire rules]#
当您首次安装 IPFire 时,它设置的唯一用户帐户是 root 用户。但是,有工具可以创建普通用户帐户并赋予其sudo
权限。我还没有在这台机器上做这个操作,因为我想向您展示默认配置。但是,在生产机器上我肯定会这样做。然后我会禁用 root 帐户。
当您打开这些规则文件时,您会发现其中许多规则是禁用的,而相对较少的是启用的。禁用的规则前面有一个#
号,就像community.rules
文件中的这两个规则一样:
#alert tcp $HOME_NET 2589 -> $EXTERNAL_NET any (msg:"MALWARE-BACKDOOR - Dagger_1.4.0"; flow:to_client,established; content:"2|00 00 00 06 00 00 00|Drives|24 00|"; depth:16; metadata:ruleset community; classtype:misc-activity; sid:105; rev:14;)
#alert tcp $EXTERNAL_NET any -> $HOME_NET 7597 (msg:"MALWARE-BACKDOOR QAZ Worm Client Login access"; flow:to_server,established; content:"qazwsx.hsq"; metadata:ruleset community; reference:mcafee,98775; classtype:misc-activity; sid:108; rev:11;)
您可能还注意到每个规则都以关键字alert
开头。您可以使用grep
快速检查文件中启用的规则:
[root@ipfire rules]# grep ^alert community.rules | less
[root@ipfire rules]#
^
字符表示我正在community.rules
文件中搜索以单词alert
开头的每一行,而不带前面的#
号。将输出导入less
是可选的,但它可以帮助您更好地查看所有输出数据。您还可以使用通配符一次搜索所有文件:
[root@ipfire rules]# grep ^alert *.rules | less
[root@ipfire rules]#
您需要查看规则以确定您需要哪些规则,哪些规则不需要。通过删除规则前面的#
号来启用所需的规则,并通过在规则前面放置#
号来禁用不需要的规则。
不幸的是,IPFire 不包括用于可视化 Snort 数据的图形前端,但它确实带有 IDS 日志查看器:
IPFire 还有许多其他很酷的功能,我还没有提到。这些功能包括内置的虚拟专用网络(VPN)功能,内置的 DHCP 服务器,内置的动态 DNS 服务器和服务质量控制。最好的部分是它是完全免费的,除非您想购买订阅以始终获得最新的 Snort 规则。
您可以从他们的网站下载 IPFire:www.ipfire.org/.
使用 Security Onion
好吧,也许带有内置 Snort 的防火墙设备现在不是您需要的。也许您需要的是一个完整的 NIDS。但是,您是一个忙碌的人,需要快速简便的东西,而且您的老板对您的预算要求相当严格。那么,您该怎么办呢?
Security Onion 是一个免费的专业 Linux 发行版,构建在 Xubuntu 长期支持(LTS)发行版之上。它包括完整的 Snort 实现,几乎包括您可以想象的所有图形功能,以帮助您可视化网络上发生的情况。如果您可以安装 Linux 发行版并在安装后进行一些点对点的配置,那么您就可以安装 Security Onion。
请注意,Security Onion 所基于的 Xubuntu LTS 版本始终至少落后于当前 Xubuntu LTS 版本。在撰写本文时,当前的 Xubuntu LTS 版本是版本 16.04,而 Security Onion 仍然基于 Xubuntu 14.04。但是,这可能会在您阅读本书时发生变化。
此外,如果您想尝试 Security Onion,您可以在 VirtualBox 虚拟机中设置它。创建虚拟机时,将其设置为两个网络适配器,都处于Bridged模式。为了获得最佳性能,至少分配 3GB 内存。
安装完操作系统后,配置只是简单地双击设置图标,然后按照对话框进行操作:
要设置具有传感器功能的机器,您需要一台具有两个接口卡的机器。一个接口将分配 IP 地址,将成为管理接口:
您可以将管理界面设置为通过 DHCP 自动获取 IP 地址,但最好分配一个静态 IP 地址:
您将使用另一个网络适配器作为嗅探接口。您不会为其分配 IP 地址,因为您希望该接口对坏人不可见:
确认您选择的网络配置后,重新启动机器:
机器重新启动后,再次双击设置图标,但这次选择跳过网络配置。对于第一次使用 Security Onion 的用户来说,评估模式非常有帮助,因为它会自动选择大多数东西的最正确选项。
从现在开始,只需确认哪个网络接口将成为嗅探接口,并填写不同图形界面的登录凭据。然后,在等待设置实用程序下载 Snort 规则并执行最后的配置步骤后,您将拥有自己的操作 NIDS。现在我问,还有什么比这更容易的呢?
Security Onion 配备了几种不同的图形界面。我最喜欢的是 Squert,如图所示。即使只有默认的检测规则,我已经看到了一些有趣的东西。以下截图显示了 Squert:
首先,我看到网络上有人在挖掘一些 Monero 加密货币。好吧,实际上,我就是在挖,所以没关系。但是,能够检测到这一点是件好事,因为众所周知,坏人曾经在企业服务器上种植 Monero 挖矿软件以谋取私利。Monero 加密货币挖矿会给服务器的 CPU 带来很大负载,所以这不是你想要的服务器上的东西。此外,一些狡猾的网站运营商在其网页上放置了 JavaScript 代码,导致任何访问它们的计算机都开始挖掘 Monero。因此,这条规则也有助于保护桌面系统。
我还看到 Dropbox 客户端正在广播,这也没关系,因为我是 Dropbox 用户。但是,这也是您可能不希望在企业网络上拥有的东西。
要查看与特定项目相关联的 Snort 规则,只需单击该项目:
这只是一个已经为我们设置好的标准 Snort 规则。
想要挖掘 Monero 而不付费的坏人已经建立了被感染其挖矿软件的机器的僵尸网络。在一些攻击中,只有 Windows 服务器被感染。但是,这里有一个情况,Windows 和 Linux 服务器都被感染了:
单击 Squert 的“视图”选项卡,您将看到您的机器建立的连接的图形表示:
关于 Security Onion 和 Snort,我还可以向您展示更多,但是,空间不允许。我已经给了您要领,现在去尝试一下吧。
我知道我让 Snort/Security Onion 看起来相当简单,但实际上比我能向您展示的要复杂得多。在大型网络上,您可能会看到很多看起来毫无意义的流量,除非您知道如何解释 Snort 向您呈现的信息。您可能还需要微调您的 Snort 规则,以便看到您想要看到的异常情况,而不会产生错误的警报。或者,您甚至可能需要编写自己的自定义 Snort 规则来处理异常情况。幸运的是,Security Onion 团队提供培训,包括现场和在线培训。您可以在以下网站了解更多信息:
使用 Lynis 进行扫描和加固
Lynis 是另一个可以用来扫描系统漏洞和不良安全配置的自由开源软件工具。它是一个便携式 shell 脚本,不仅可以在 Linux 上使用,还可以在各种不同的 Unix 系统和类 Unix 系统上使用。它是一个多用途工具,您可以用它进行合规性审计、漏洞扫描或加固。与大多数漏洞扫描工具不同,您需要在要扫描的系统上安装和运行 Lynis。根据 Lynis 的创建者,这样可以进行更深入的扫描。
Lynis 扫描工具有免费版本,但其扫描能力有限。如果您需要 Lynis 提供的所有功能,您需要购买企业许可证。
在 Red Hat/CentOS 上安装 Lynis
Red Hat/CentOS 用户将在 EPEL 存储库中找到最新版本的 Lynis。因此,如果您已安装了 EPEL,就像我在第一章中向您展示的那样,在虚拟环境上运行 Linux,安装只是一个简单的事情:
sudo yum install lynis
在 Ubuntu 上安装 Lynis
Ubuntu 在其自己的存储库中有 Lynis,但您获得的版本取决于您使用的 Ubuntu 版本。Ubuntu 16.04 LTS 存储库中的版本相对较旧。Ubuntu 17.10 存储库中的版本更新一些,但仍不完全是最新的。在任何情况下,安装 Lynis 的命令是:
sudo apt install lynis
如果您想要 Ubuntu 的最新版本,或者想要在没有 Lynis 的存储库中使用 Lynis 的操作系统上使用它,您可以从作者的网站上下载。
您可以从cisofy.com/downloads/lynis/.
下载 Lynis。这个很酷的地方是,一旦您下载了它,您可以在任何 Linux、Unix 或类 Unix 操作系统上使用它。(这甚至包括 MacOS,我刚刚通过在运行 macOS High Sierra 的旧 Mac Pro 上运行它来确认。)
由于可执行文件只是一个普通的 shell 脚本,因此无需执行实际安装。您只需要解压缩存档文件,cd
进入生成的目录,并从那里运行 Lynis:
tar xzvf lynis-2.5.7.tar.gz
cd lynis
sudo ./lynis -h
lynis -h
命令显示帮助屏幕,其中包含您需要了解的所有 Lynis 命令。
使用 Lynis 进行扫描
无论您要扫描哪个操作系统,Lynis 命令都是相同的。唯一的区别是,如果您从网站下载的存档文件中运行它,您将cd
进入lynis
目录,并在lynis
命令之前加上./
。(这是因为出于安全原因,您自己的主目录不在允许 shell 自动查找可执行文件的路径设置中。)
要扫描已安装 Lynis 的系统,请按照以下步骤进行:
sudo lynis audit system
要扫描刚刚下载存档文件的系统,请按照以下步骤进行:
cd lynis
sudo ./lynis audit system
从您的主目录中的 shell 脚本运行 Lynis 会显示以下消息:
donnie@ubuntu:~/lynis$ sudo ./lynis audit system
[sudo] password for donnie:
[!] Change ownership of /home/donnie/lynis/include/functions to 'root' or similar (found: donnie with UID 1000).
Command:
# chown 0:0 /home/donnie/lynis/include/functions
[X] Security check failed
Why do I see this error?
-------------------------------
This is a protection mechanism to prevent the root user from executing user created files. The files may be altered, or including malicious pieces of script.
What can I do?
---------------------
Option 1) Check if a trusted user created the files (e.g. due to using Git, Homebrew or similar).
If you trust these files, you can decide to continue this run by pressing ENTER.
Option 2) Change ownership of the related files (or full directory).
Commands (full directory):
# cd ..
# chown -R 0:0 lynis
# cd lynis
# ./lynis audit system
[ Press ENTER to continue, or CTRL+C to cancel ]
这不会造成任何损害,所以你可以按Enter继续。或者,如果看到这条消息真的让你烦恼,你可以按照消息告诉你的那样,将 Lynis 文件的所有权更改为 root 用户。现在,我只是按下Enter。
以这种方式运行 Lynis 扫描类似于运行 OpenSCAP 扫描以符合通用安全配置文件。主要区别在于 OpenSCAP 具有自动修复功能,而 Lynis 没有。Lynis 告诉你它发现了什么,并建议如何修复它认为是问题的东西,但它不会为你修复任何东西。
空间不允许我展示整个扫描输出,但我可以给你展示一些示例片段:
[+] Boot and services
------------------------------------
- Service Manager [ systemd ]
- Checking UEFI boot [ DISABLED ]
- Checking presence GRUB [ OK ]
- Checking presence GRUB2 [ FOUND ]
- Checking for password protection [ WARNING ]
- Check running services (systemctl) [ DONE ]
Result: found 21 running services
- Check enabled services at boot (systemctl) [ DONE ]
Result: found 28 enabled services
- Check startup files (permissions) [ OK ]
警告消息显示我没有为我的GRUB2
引导加载程序设置密码保护。这可能很重要,也可能不重要,因为有人可以利用这一点来获得对机器的物理访问权限。如果这是一个被锁在只有少数信任人员可以访问的房间里的服务器,那么我不会担心,除非适用的监管机构的规定要求我这样做。如果这是一个放在开放式隔间里的台式机,那么我肯定会修复这个问题。(我们将在第十章中看到 GRUB 密码保护,忙碌蜜蜂的安全提示和技巧。)
在“文件系统”部分,我们看到一些带有“建议”标志的项目。
[+] File systems
------------------------------------
- Checking mount points
- Checking /home mount point [ SUGGESTION ]
- Checking /tmp mount point [ SUGGESTION ]
- Checking /var mount point [ SUGGESTION ]
- Query swap partitions (fstab) [ OK ]
- Testing swap partitions [ OK ]
- Testing /proc mount (hidepid) [ SUGGESTION ]
- Checking for old files in /tmp [ OK ]
- Checking /tmp sticky bit [ OK ]
- ACL support root file system [ ENABLED ]
- Mount options of / [ NON DEFAULT ]
- Checking Locate database [ FOUND ]
- Disable kernel support of some filesystems
- Discovered kernel modules: cramfs freevxfs hfs hfsplus jffs2 udf
正是 Lynis 建议的内容出现在输出的最后:
. . .
. . .
* To decrease the impact of a full /home file system, place /home on a separated partition [FILE-6310]
https://cisofy.com/controls/FILE-6310/
* To decrease the impact of a full /tmp file system, place /tmp on a separated partition [FILE-6310]
https://cisofy.com/controls/FILE-6310/
* To decrease the impact of a full /var file system, place /var on a separated partition [FILE-6310]
https://cisofy.com/controls/FILE-6310/
. . .
. . .
我们将看看输出的最后一个部分,即扫描详细信息部分:
Lynis security scan details:
Hardening index : 67 [############# ]
Tests performed : 218
Plugins enabled : 0
Components:
- Firewall [V]
- Malware scanner [X]
Lynis Modules:
- Compliance Status [?]
- Security Audit [V]
- Vulnerability Scan [V]
Files:
- Test and debug information : /var/log/lynis.log
- Report data : /var/log/lynis-report.dat
对于“组件”,“恶意软件扫描器”旁边有一个红色的X
。这是因为我没有在这台机器上安装 ClamAV 或maldet
,所以 Lynis 无法进行病毒扫描。
对于“Lynis 模块”,我们看到“合规状态”旁边有一个问号。这是因为这个功能是为 Lynis 企业版保留的,需要付费订阅。正如我们在上一章中看到的,你可以使用 OpenSCAP 配置文件使系统符合几种不同的安全标准,而且这不需要花费任何费用。使用 Lynis,你必须为合规配置文件付费,但你可以选择更广泛的范围。除了 OpenSCAP 提供的合规配置文件外,Lynis 还提供了 HIPAA 和萨班斯-奥克斯合规配置文件。
如果你在美国,你肯定知道 HIPAA 和萨班斯-奥克斯是什么,以及它们是否适用于你。如果你不在美国,那么你可能不需要担心它们。
话虽如此,如果你在医疗行业工作,即使你不在美国,HIPAA 配置文件也可以为你提供如何保护患者的私人数据的指导。
关于 Lynis,我想说的最后一件事是关于企业版。在他们网站上的这张截图中,你可以看到当前的定价和不同订阅计划之间的区别:
正如你所看到的,你有选择。
在这个网站上你会找到有关定价的信息:
这基本上就是我们对 Lynis 的讨论。接下来,让我们看看一个外部漏洞扫描器。
使用 OpenVAS 查找漏洞
开放漏洞评估扫描器(OpenVAS)是你用来执行远程漏洞扫描的工具。你可以扫描单台机器、一组相似的机器或整个网络。它不包含在主要 Linux 发行版的软件仓库中,所以最好的方法是安装专门的安全发行版之一来获取它。
三大安全发行版是 Kali Linux、Parrot Linux 和 Black Arch。它们面向安全研究人员和渗透测试人员,但它们包含的工具也适用于 Linux 或 Windows 的普通安全管理员。OpenVAS 就是其中之一。这三个安全发行版都有各自独特的优势和劣势,但由于 Kali 最受欢迎,我们将用它进行演示。
您可以从www.kali.org/downloads/.
下载 Kali Linux
当您转到 Kali 下载页面时,您会看到很多选择。如果您像我一样不喜欢默认的 Gnome 3 桌面环境,您可以选择其他内容。我个人是 LXDE 的粉丝,所以我会选择它:
Kali 是基于 Debian Linux 构建的,因此安装它与安装 Debian 几乎相同。唯一的例外是 Kali 安装程序允许您为 root 用户创建密码,但不允许您创建普通的非 root 用户帐户。这是因为您在 Kali 中几乎所有操作都需要以 root 用户身份登录。我知道这与我一直告诉您的不要以root
身份登录以及使用sudo
而不是普通用户帐户登录的建议相悖。但是,您在 Kali 中需要做的大部分工作都无法使用sudo
完成。此外,Kali 并不是用作通用发行版,只要您按照其预期使用,以 root 身份登录就可以。
OpenVAS 是一个占用内存较多的程序,因此如果您在虚拟机中安装 Kali,请确保至少分配 3GB 的内存。
安装 Kali 后,您需要做的第一件事是更新它,这与更新任何 Debian/Ubuntu 类型的发行版的方式相同。然后,按照以下方式安装 OpenVAS:
apt update
apt dist-upgrade
apt install openvas
OpenVAS 安装完成后,您需要运行一个脚本,该脚本将创建安全证书并下载漏洞数据库:
openvas-setup
这将需要很长时间,所以在运行时您可以去拿一个三明治和一杯咖啡。最终完成后,您将看到用于登录 OpenVAS 的密码。记下来并保存在安全的地方:
您可以从应用程序菜单控制和更新 OpenVAS:
在菜单中,单击 openvas start。然后,打开 Firefox 并导航到https://localhost:9392
。您会收到一个安全警告,因为 OpenVAS 使用自签名的安全证书,但没关系。只需单击“高级”按钮,然后单击“添加异常”:
在登录页面,输入admin
作为用户,然后输入由openvas-setup
脚本生成的密码。
现在,OpenVAS 有各种花哨的功能,但现在我们只看如何进行基本的漏洞扫描。首先,从 OpenVAS 仪表板的扫描菜单中选择“任务”:
这将弹出对话框,告诉您使用向导。(没错,我们要去见向导。):
关闭对话框后,您会看到紫色的向导图标出现在左上角。现在,我们只需选择“任务向导”选项,它将为我们选择所有默认的扫描设置:
您需要做的唯一事情是输入要扫描的机器的 IP 地址,然后开始扫描:
扫描需要一些时间,所以在运行时您可以去拿一个三明治和一杯咖啡。
你正在进行的扫描类型被称为全面和快速,这不是最全面的扫描类型。要选择另一种扫描类型并配置其他扫描选项,请使用高级任务向导,如下面的截图所示:
在这里,你可以看到不同扫描选项的下拉列表:
当我使用默认的全面和快速选项进行第一次扫描时,我没有发现太多问题。我发现了一个中等严重性和 18 个低严重性的问题,就这些。由于我扫描的机器的年龄,我知道肯定会有更多问题,所以我尝试了全面和快速终极选项。这一次,我发现了更多问题,包括一些高严重性的问题:
报告显示,我的机器正在使用弱加密算法进行 Secure Shell,这被分类为中等严重性。它还有一个被分类为高严重性问题的打印服务器漏洞。
你还需要注意那些没有标记为漏洞的项目。例如,VNC 安全类型项显示端口5900
是开放的。这意味着虚拟网络计算(VNC)守护程序正在运行,允许用户远程登录到这台机器的桌面。如果这台机器是一个面向互联网的机器,那将是一个真正的问题,因为 VNC 没有像 Secure Shell 那样的真正安全性。
点击打印服务器项目,我可以看到对这个漏洞的解释。
请记住,目标机器在这种情况下是一台台式机。如果它是一台服务器,很可能会出现更多问题。
这基本上就是 OpenVAS 的全部内容了。正如我之前所说,你可以用它做很多很棒的事情。但是,我在这里向你展示的应该足够让你入门了。尝试使用不同的扫描选项来玩耍,看看结果的差异。
如果你想了解更多关于 Kali Linux 的信息,你可以在 Packt Publishing 网站上找到很多关于它的书籍。
使用 Nikto 进行 Web 服务器扫描
我们刚刚看到的 OpenVAS 是一个通用的漏洞扫描器。它可以找到任何操作系统或服务器守护程序的漏洞。然而,正如我们刚刚看到的,OpenVAS 扫描可能需要一段时间才能运行,并且可能超出你的需求。
Nikto 是一个专用工具,只有一个目的。也就是说,它的目的是扫描 Web 服务器,只有 Web 服务器。它易于安装,易于使用,并且能够相当快速地对 Web 服务器进行全面扫描。虽然它包含在 Kali Linux 中,但你不需要 Kali Linux 来运行它。
Kali Linux 中的 Nikto
如果你已经有 Kali Linux,你会发现 nikto 已经安装在漏洞分析菜单下:
当你点击菜单项时,你会打开一个带有 Nikto 帮助屏幕显示的命令行终端:
在 Linux 上安装和更新 Nikto
Nikto 在 Red Hat/CentOS 的 EPEL 仓库中,而在 Ubuntu 的正常仓库中。除了 Nikto 软件包本身,你还需要安装一个允许 Nikto 扫描设置了 SSL/TLS 加密的 Web 服务器的软件包。
在 Red Hat/CentOS 上安装:
sudo yum install nikto perl-Net-SSLeay
在 Ubuntu 上安装:
sudo apt install nikto libnet-ssleay-perl
接下来你需要做的是更新漏洞签名数据库。但是,在撰写本文时,Red Hat/CentOS 实现中存在一个轻微的错误。由于某种原因,docs
目录丢失,这意味着更新功能将无法下载CHANGES.txt
文件,以向您展示新数据库更新的变化。要在您的 CentOS 虚拟机上修复这个问题,请使用以下命令:
sudo mkdir /usr/share/nikto/docs
不过请记住,到你读到这篇文章的时候,这些问题可能已经被修复了。
从现在开始,无论你的虚拟机是哪一个,事情都会一样。要更新漏洞数据库,请使用以下命令:
sudo nikto -update
Nikto 本身不需要sudo
权限,但更新它需要,因为它需要写入普通用户无法写入的目录。
使用 Nikto 扫描 Web 服务器
从现在开始,你不再需要sudo
权限。所以,你可以暂时不用输入密码了。
要进行简单的扫描,使用-h
选项指定目标主机:
nikto -h 192.168.0.9
nikto -h www.example.com
让我们来看一些示例输出:
+ Allowed HTTP Methods: POST, OPTIONS, GET, HEAD
+ OSVDB-396: /_vti_bin/shtml.exe: Attackers may be able to crash FrontPage by requesting a DOS device, like shtml.exe/aux.htm -- a DoS was not attempted.
+ /cgi-bin/guestbook.pl: May allow attackers to execute commands as the web daemon.
+ /cgi-bin/wwwadmin.pl: Administration CGI?
+ /cgi-bin/Count.cgi: This may allow attackers to execute arbitrary commands on the server
+ OSVDB-28260: /_vti_bin/shtml.exe/_vti_rpc?method=server+version%3a4%2e0%2e2%2e2611: Gives info about server settings.
+ OSVDB-3092: /_vti_bin/_vti_aut/author.exe?method=list+documents%3a3%2e0%2e2%2e1706&service%5fname=&listHiddenDocs=true&listExplorerDocs=true&listRecurse=false&listFiles=true&listFolders=true&listLinkInfo=true&listIncludeParent=true&listDerivedT=false&listBorders=fals: We seem to have authoring access to the FrontPage web.
+ OSVDB-250: /wwwboard/passwd.txt: The wwwboard password file is browsable. Change wwwboard to store this file elsewhere, or upgrade to the latest version.
+ OSVDB-3092: /stats/: This might be interesting...
+ OSVDB-3092: /test.html: This might be interesting...
+ OSVDB-3092: /webstats/: This might be interesting...
+ OSVDB-3092: /cgi-bin/wwwboard.pl: This might be interesting...
+ OSVDB-3233: /_vti_bin/shtml.exe/_vti_rpc: FrontPage may be installed.
+ 6545 items checked: 0 error(s) and 15 item(s) reported on remote host
+ End Time: 2017-12-24 10:54:21 (GMT-5) (678 seconds)
在顶部,我们看到vti_bin
目录中有一个shtml.exe
文件,据说是用于 FrontPage Web 编写程序的。我不知道为什么会有这个文件,考虑到这是一个 Linux 服务器,那是一个 Windows 可执行文件。Nikto 告诉我,通过拥有那个文件,某人可能会对我进行拒绝服务(DOS)攻击。
接下来,我们看到/cgi-bin
目录中有各种脚本。你可以从解释性消息中看出这不是一件好事,因为这可能允许攻击者在我的服务器上执行命令。
在这之后,我们看到vti_bin
目录中有一个author.exe
文件,这理论上可能允许某人拥有作者权限。
最后一个有趣的项目是wwwboard
目录中的passwd.txt
文件。显然,这个密码文件是可浏览的,这绝对不是一件好事。
现在,在你指责我捏造这些问题之前,我要透露这是对一个真实托管服务上的真实生产网站的扫描。(是的,我有扫描的许可。)所以,这些问题是真实存在的,需要修复。
以下是我从扫描运行 WordPress 的 Web 服务器中得到的另外两个示例消息:
HTTP TRACK method is active, suggesting the host is vulnerable to XST
Cookie wordpress_test_cookie created without the httponly flag
长话短说,这两个问题都有可能允许攻击者窃取用户凭据。在这种情况下,解决方法是查看 WordPress 团队是否发布了任何可以解决问题的更新。
那么,我们如何保护 Web 服务器免受这些漏洞的影响呢?
-
正如我们在第一个示例中看到的,你希望确保你的 Web 服务器上没有任何风险的可执行文件。在这种情况下,我们发现了两个
.exe
文件,可能不会对我们的 Linux 服务器造成任何伤害,因为 Windows 可执行文件无法在 Linux 上运行。然而,另一方面,它可能是一个伪装成 Windows 可执行文件的 Linux 可执行文件。我们还发现了一些perl
脚本,这些脚本肯定会在 Linux 上运行,并可能会造成问题。 -
如果有人在你的 Web 服务器上植入了一些恶意脚本,你会希望有某种强制访问控制,比如 SELinux 或 AppArmor,可以阻止恶意脚本运行。(有关详细信息,请参阅第七章,使用 SELinux 和 AppArmor 实施强制访问控制。)
-
你可能还考虑安装 Web 应用防火墙,比如ModSecurity。空间不允许我详细介绍 ModSecurity 的细节,但你可以在 Packt Publishing 网站找到一本介绍它的书。
-
保持系统更新,特别是如果你正在运行基于 PHP 的内容管理系统,比如 WordPress。(如果你关注 IT 安全新闻,你会发现关于 WordPress 漏洞的报道比你想象的要频繁。)
还有其他的扫描选项,你可以在命令行中输入nikto
来查看。不过,现在这些已经足够让你开始进行基本的 Web 服务器扫描了。
总结
我们已经在我们的旅程中达到了又一个里程碑,并且看到了一些很酷的东西。我们从讨论设置 Snort 作为 NIDS 的基础知识开始。然后我向你展示了如何通过部署已经设置好并准备就绪的专业 Linux 发行版来严重作弊。
接下来,我向你介绍了 Lynis 以及如何使用它来扫描系统中的各种漏洞和合规性问题。最后,我们通过 OpenVAS 和 Nikto 的实际演示结束了这一切。
在下一章中,我们将以一些忙碌管理员的快速提示来结束整个旅程。我会在那里见到你。
第十章:对于繁忙的用户的安全提示和技巧
在我们的最后一章中,我想对之前章节中不一定适合的一些快速提示和技巧进行总结。把这些提示看作是繁忙管理员的时间节省者。
我们将涵盖以下主题:
-
快速审计系统服务的方法
-
对 GRUB2 配置进行密码保护
-
安全配置然后对 UEFI/BIOS 进行密码保护
-
在设置系统时使用安全检查表
审计系统服务
服务器管理的一个基本原则,无论我们谈论哪个操作系统,都是在服务器上永远不要安装任何你绝对不需要的东西。特别是你不希望任何不必要的网络服务在运行,因为这会给坏人额外的进入系统的途径。而且,总是有可能一些邪恶的黑客可能已经植入了一些充当网络服务的东西,你肯定想知道这件事。在本章中,我们将看一些审计系统的不同方法,以确保系统上没有不必要的网络服务在运行。
使用 systemctl 审计系统服务
在带有 systemd 的 Linux 系统中,systemctl
命令几乎是一个为您执行许多操作的通用命令。除了控制系统的服务,它还可以显示这些服务的状态。我们有以下代码:
donnie@linux-0ro8:~> sudo systemctl -t service --state=active
以下是前述命令的分解:
-
-t service
:我们想要查看关于系统上服务或者以前称为守护进程的信息 -
--state=active
:这指定我们想要查看实际正在运行的所有系统服务的信息
这个命令的部分输出看起来像这样:
UNIT LOAD ACTIVE SUB DESCRIPTION
accounts-daemon.service loaded active running Accounts Service
after-local.service loaded active exited /etc/init.d/after.local Compatibility
alsa-restore.service loaded active exited Save/Restore Sound Card State
apparmor.service loaded active exited Load AppArmor profiles
auditd.service loaded active running Security Auditing Service
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
cron.service loaded active running Command Scheduler
. . .
. . .
systemd-sysctl.service loaded active exited Apply Kernel Variables
systemd-tmpfiles-setup-dev.service loaded active exited Create Static Device Nodes in /dev
systemd-tmpfiles-setup.service loaded active exited Create Volatile Files and Directories
systemd-udev-root-symlink.service loaded active exited Rule generator for /dev/root symlink
systemd-udev-trigger.service loaded active exited udev Coldplug all Devices
systemd-udevd.service loaded active running udev Kernel Device Manager
systemd-update-utmp.service loaded active exited Update UTMP about System Boot/Shutdown
通常你不会想看到这么多信息,尽管有时可能会需要。这个命令显示了系统上运行的每个服务的状态。现在真正让我们感兴趣的是可以允许某人连接到你的系统的网络服务。所以,让我们看看如何缩小范围。
使用 netstat 审计网络服务
以下是你想要跟踪系统上正在运行的网络服务的两个原因:
-
确保没有不需要的合法网络服务正在运行
-
确保你没有任何恶意软件在监听来自其主机的网络连接
netstat
命令对于这些情况既方便又易于使用。首先,假设你想要查看正在监听并等待有人连接的网络服务列表:
donnie@linux-0ro8:~> netstat -lp -A inet
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 *:ideafarm-door *:* LISTEN -
tcp 0 0 localhost:40432 *:* LISTEN 3296/SpiderOakONE
tcp 0 0 *:ssh *:* LISTEN -
tcp 0 0 localhost:ipp *:* LISTEN -
tcp 0 0 localhost:smtp *:* LISTEN -
tcp 0 0 *:db-lsp *:* LISTEN 3246/dropbox
tcp 0 0 *:37468 *:* LISTEN 3296/SpiderOakONE
tcp 0 0 localhost:17600 *:* LISTEN 3246/dropbox
tcp 0 0 localhost:17603 *:* LISTEN 3246/dropbox
udp 0 0 *:57228 *:* 3376/plugin-contain
udp 0 0 192.168.204.1:ntp *:* -
udp 0 0 172.16.249.1:ntp *:* -
udp 0 0 linux-0ro8:ntp *:* -
udp 0 0 localhost:ntp *:* -
udp 0 0 *:ntp *:* -
udp 0 0 *:58102 *:* 5598/chromium --pas
udp 0 0 *:db-lsp-disc *:* 3246/dropbox
udp 0 0 *:43782 *:* 5598/chromium --pas
udp 0 0 *:36764 *:* -
udp 0 0 *:21327 *:* 3296/SpiderOakONE
udp 0 0 *:mdns *:* 5598/chromium --pas
udp 0 0 *:mdns *:* 5598/chromium --pas
udp 0 0 *:mdns *:* 5598/chromium --pas
udp 0 0 *:mdns *:* -
raw 0 0 *:icmp *:* 7 -
donnie@linux-0ro8:~>
分解如下:
-
-lp
:l
表示我们想要查看哪些网络端口正在监听。换句话说,我们想要查看哪些网络端口正在等待连接。p
表示我们想要查看每个端口上正在监听的程序或服务的名称和进程 ID 号。 -
-A inet
:这意味着我们只想要查看属于inet
系列的网络协议的信息。换句话说,我们想要查看关于raw
、tcp
和udp
网络套接字的信息,但我们不想看到任何关于仅处理操作系统内部进程通信的 Unix 套接字的信息。
由于这个输出来自我目前正在使用的 OpenSUSE 工作站,你在这里看不到通常的服务器类型服务。但是,你会看到一些你可能不想在你的服务器上看到的东西。例如,让我们看看第一项:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 *:ideafarm-door *:* LISTEN -
本地地址
列指定了这个监听套接字的本地地址和端口。星号表示这个套接字在本地网络上,ideafarm-door
是正在监听的网络端口的名称。(默认情况下,netstat
会尽可能地显示端口的名称,通过从/etc/services
文件中提取端口信息。)
现在,因为我不知道ideafarm-door
服务是什么,我使用了我最喜欢的搜索引擎来找出答案。通过将术语ideafarm-door
输入 DuckDuckGo,我找到了答案:
顶部搜索结果将我带到了一个名为WhatPortIs的网站。根据这个网站,ideafarm-door
实际上是端口902
,属于 VMware Server Console。好的,这很合理,因为我确实在这台机器上安装了 VMware Player。所以,一切都很好。
您可以在WhatPortIs网站上查看:whatportis.com/
。
接下来是:
tcp 0 0 localhost:40432 *:* LISTEN 3296/SpiderOakONE
此项目显示本地地址为localhost
,监听端口为端口40432
。这次,PID/Program Name
列实际上告诉了我们这是什么。SpiderOak ONE是一个基于云的备份服务,您可能希望在服务器上运行它,也可能不希望。
现在,让我们再看几个项目:
tcp 0 0 *:db-lsp *:* LISTEN 3246/dropbox
tcp 0 0 *:37468 *:* LISTEN 3296/SpiderOakONE
tcp 0 0 localhost:17600 *:* LISTEN 3246/dropbox
tcp 0 0 localhost:17603 *:* LISTEN 3246/dropbox
在这里,我们看到 Dropbox 和 SpiderOak ONE 都在本地地址上带有星号。因此,它们都在使用本地网络地址。Dropbox 的端口名称是db-lsp
,代表Dropbox LAN Sync Protocol。SpiderOak ONE 端口没有官方名称,所以只列为端口37468
。最后两行显示 Dropbox 还使用本地机器的地址,端口为17600
和17603
。
到目前为止,我们只看了 TCP 网络套接字。让我们看看它们与 UDP 套接字有何不同:
udp 0 0 192.168.204.1:ntp *:* -
udp 0 0 172.16.249.1:ntp *:* -
udp 0 0 linux-0ro8:ntp *:* -
首先要注意的是State
列下面没有任何内容。这是因为在 UDP 中,没有状态。它们实际上是在等待数据包进来,并准备发送数据包出去。但由于这几乎是 UDP 套接字所能做的全部,所以没有必要为它们定义不同的状态。
在前两行中,我们看到一些奇怪的本地地址。这是因为我在这台工作站上安装了 VMware Player 和 VirtualBox。这两个套接字的本地地址是 VMware 和 VirtualBox 虚拟网络适配器的地址。最后一行显示了我的 OpenSUSE 工作站的主机名作为本地地址。在这三种情况下,端口都是用于时间同步的网络时间协议端口。
现在让我们看一下最后一组 UDP 项目:
udp 0 0 *:58102 *:* 5598/chromium --pas
udp 0 0 *:db-lsp-disc *:* 3246/dropbox
udp 0 0 *:43782 *:* 5598/chromium --pas
udp 0 0 *:36764 *:* -
udp 0 0 *:21327 *:* 3296/SpiderOakONE
udp 0 0 *:mdns *:* 5598/chromium --pas
在这里,我们看到我的 Chromium 网络浏览器已准备好在几个不同的端口上接受网络数据包。我们还看到 Dropbox 使用 UDP 来接受其他安装了 Dropbox 的本地机器的发现请求。我猜端口21327
对 SpiderOak ONE 执行相同的功能。
当然,由于这台机器是我的主力工作站,Dropbox 和 SpiderOak ONE 对我来说几乎是必不可少的。我自己安装了它们,所以我一直知道它们在那里。但是,如果您在服务器上看到类似的情况,您将希望调查一下服务器管理员是否知道这些程序已安装,然后找出它们为什么安装。可能它们正在执行合法的功能,也可能它们没有。
Dropbox 和 SpiderOak ONE 之间的一个区别是,使用 Dropbox 时,您的文件直到上传到 Dropbox 服务器后才会被加密。因此,Dropbox 的人员拥有您文件的加密密钥。另一方面,SpiderOak ONE 在本地机器上对文件进行加密,加密密钥永远不会离开您的手中。因此,如果您确实需要云备份服务并且正在处理敏感文件,像 SpiderOak ONE 这样的服务肯定比 Dropbox 更好。 (不,SpiderOak ONE 的人员并没有付我来说这些话。)
如果您想查看端口号和 IP 地址而不是网络名称,请添加n
选项。我们有以下代码:
donnie@linux-0ro8:~> netstat -lpn -A inet
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:902 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:40432 0.0.0.0:* LISTEN 3296/SpiderOakONE
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:17500 0.0.0.0:* LISTEN 3246/dropbox
tcp 0 0 0.0.0.0:37468 0.0.0.0:* LISTEN 3296/SpiderOakONE
tcp 0 0 127.0.0.1:17600 0.0.0.0:* LISTEN 3246/dropbox
tcp 0 0 127.0.0.1:17603 0.0.0.0:* LISTEN 3246/dropbox
udp 0 0 192.168.204.1:123 0.0.0.0:* -
udp 0 0 172.16.249.1:123 0.0.0.0:* -
udp 0 0 192.168.0.222:123 0.0.0.0:* -
udp 0 0 127.0.0.1:123 0.0.0.0:* -
udp 0 0 0.0.0.0:123 0.0.0.0:* -
udp 0 0 0.0.0.0:17500 0.0.0.0:* 3246/dropbox
udp 0 0 0.0.0.0:50857 0.0.0.0:* 5598/chromium --pas
udp 0 0 0.0.0.0:43782 0.0.0.0:* 5598/chromium --pas
udp 0 0 0.0.0.0:44023 0.0.0.0:* 10212/plugin-contai
udp 0 0 0.0.0.0:36764 0.0.0.0:* -
udp 0 0 0.0.0.0:21327 0.0.0.0:* 3296/SpiderOakONE
udp 0 0 0.0.0.0:5353 0.0.0.0:* 5598/chromium --pas
udp 0 0 0.0.0.0:5353 0.0.0.0:* 5598/chromium --pas
udp 0 0 0.0.0.0:5353 0.0.0.0:* 5598/chromium --pas
udp 0 0 0.0.0.0:5353 0.0.0.0:* -
raw 0 0 0.0.0.0:1 0.0.0.0:* 7 -
donnie@linux-0ro8:~>
只需省略l
选项即可查看已建立的 TCP 连接。在我的工作站上,这会生成一个非常长的列表,所以我只会显示一些项目:
donnie@linux-0ro8:~> netstat -p -A inet
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 1 0 linux-0ro8:41670 ec2-54-88-208-223:https CLOSE_WAIT 3246/dropbox
tcp 0 0 linux-0ro8:59810 74-126-144-106.wa:https ESTABLISHED 3296/SpiderOakONE
tcp 0 0 linux-0ro8:58712 74-126-144-105.wa:https ESTABLISHED 3296/SpiderOakONE
tcp 0 0 linux-0ro8:caerpc atl14s78-in-f2.1e:https ESTABLISHED 10098/firefox
. . .
. . .
Foreign Address
列显示了连接远程端的机器的地址和端口号。第一项显示与 Dropbox 服务器的连接处于CLOSE_WAIT
状态。这意味着 Dropbox 服务器已关闭连接,现在我们正在等待本地机器关闭套接字。
因为那些外国地址的名称没有太多意义,让我们添加n
选项以查看 IP 地址:
donnie@linux-0ro8:~> netstat -np -A inet
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 1 192.168.0.222:59594 37.187.24.170:443 SYN_SENT 10098/firefox
tcp 0 0 192.168.0.222:59810 74.126.144.106:443 ESTABLISHED 3296/SpiderOakONE
tcp 0 0 192.168.0.222:58712 74.126.144.105:443 ESTABLISHED 3296/SpiderOakONE
tcp 0 0 192.168.0.222:38606 34.240.121.144:443 ESTABLISHED 10098/firefox
. . .
. . .
这次我们看到了一些新的东西。第一项显示了 Firefox 连接的SYN_SENT
状态。这意味着本地机器正在尝试与外国 IP 地址建立连接。此外,在Local Address
下,我们看到了我 OpenSUSE 工作站的静态 IP 地址。
如果我有空间在这里显示整个netstat
输出,您将看到Proto
列下只有tcp
。这是因为 UDP 协议不像 TCP 协议那样建立连接。
需要记住的一点是,rootkit 可以用它们自己的木马版本替换合法的 Linux 实用程序。例如,rootkit 可以有自己的netstat
的木马版本,它将显示除与 rootkit 相关的所有网络进程之外的所有网络进程。这就是为什么您需要像 Rootkit Hunter 这样的工具。
如果您需要有关netstat
的更多信息,请参阅netstat
手册页。
使用 Nmap 审计网络服务
netstat
工具非常好,可以为您提供有关网络服务情况的大量信息。稍微不足的是,您必须登录到网络上的每个主机才能使用它。
如果您想远程审计您的网络,查看每台计算机上运行的服务,而无需登录到每台计算机,那么您需要像 Nmap 这样的工具。它适用于所有主要操作系统,因此即使您被迫在工作站上使用 Windows,您也很幸运。如果您使用的是 Kali Linux,则内置了最新版本。它还在每个主要 Linux 发行版的存储库中,但通常存储库中的版本非常旧。因此,如果您使用的不是 Kali,最好的选择就是从创建者的网站下载 Nmap。
您可以从nmap.org/download.html
下载所有主要操作系统的 Nmap。
在所有情况下,您还会找到安装说明。
您将在所有操作系统上以相同的方式使用 Nmap,只有一个例外。在 Linux 和 Mac 机器上,您将在某些 Nmap 命令之前加上 sudo,在 Windows 机器上则不需要。由于我碰巧正在使用我值得信赖的 OpenSUSE 工作站,我将向您展示在 Linux 上的工作原理。让我们首先进行 SYN 数据包扫描:
donnie@linux-0ro8:~> sudo nmap -sS 192.168.0.37
Starting Nmap 6.47 ( http://nmap.org ) at 2017-12-24 19:32 EST
Nmap scan report for 192.168.0.37
Host is up (0.00016s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
22/tcp open ssh
515/tcp open printer
631/tcp open ipp
5900/tcp open vnc
MAC Address: 00:0A:95:8B:E0:C0 (Apple)
Nmap done: 1 IP address (1 host up) scanned in 57.41 seconds
donnie@linux-0ro8:~>
以下是详细信息:
-
-sS
:小写s
表示我们要执行的扫描类型。大写S
表示我们正在进行 SYN 数据包扫描。(稍后详细介绍。) -
192.168.0.37
:在这种情况下,我只扫描了一台机器。但是,我也可以扫描一组机器或整个网络。 -
Not shown: 996 closed ports
:显示所有这些关闭的端口而不是filtered
端口的事实告诉我这台机器上没有防火墙。(稍后详细介绍。)
接下来,我们看到了一系列打开的端口。(稍后详细介绍。)
这台机器的 MAC 地址表明它是某种苹果产品。稍后,我将向您展示如何获取有关它可能是什么类型的苹果产品的更多详细信息。
现在让我们更详细地看一下。
端口状态
Nmap 扫描将显示目标机器的端口处于三种状态之一:
-
filtered
:这意味着该端口被防火墙阻止 -
open
:这意味着该端口未被防火墙阻止,并且与该端口关联的服务正在运行 -
closed
:这意味着该端口没有被防火墙阻塞,并且与该端口相关的服务未运行
因此,在我们对苹果机器的扫描中,我们看到 Secure Shell 服务准备在端口22
上接受连接,打印服务准备在端口515
和631
上接受连接,以及虚拟网络计算(VNC)服务准备在端口5900
上接受连接。所有这些端口对于注重安全的管理员来说都是感兴趣的。如果 Secure Shell 正在运行,了解它是否配置安全是很有趣的。打印服务正在运行意味着这台机器设置为使用Internet Printing Protocol(IPP)。了解为什么我们使用 IPP 而不是普通的网络打印是很有趣的,也很有趣的是了解这个版本的 IPP 是否存在任何安全问题。当然,我们已经知道 VNC 不是一个安全的协议,所以我们想知道为什么它会运行。我们还看到没有端口被列为filtered
,所以我们也想知道为什么这台机器上没有防火墙。
有一个小秘密,我终于要揭露了,就是这台机器和我用来进行 OpenVAS 扫描演示的是同一台。所以,我们已经有了一些所需的信息。OpenVAS 扫描告诉我们,这台机器上的 Secure Shell 使用了弱加密算法,并且打印服务存在安全漏洞。马上,我会向你展示如何使用 Nmap 获取一些信息。
扫描类型
有很多不同的扫描选项,每个选项都有自己的目的。我们在这里使用的 SYN 数据包扫描被认为是一种隐秘的扫描类型,因为它产生的网络流量和系统日志条目比某些其他类型的扫描要少。使用这种类型的扫描,Nmap 向目标机器的一个端口发送一个 SYN 数据包,就好像它试图创建一个 TCP 连接到该机器。如果目标机器用一个 SYN/ACK 数据包回应,这意味着该端口处于open
状态,准备好创建 TCP 连接。如果目标机器用一个 RST 数据包回应,这意味着该端口处于closed
状态。如果根本没有响应,这意味着该端口是filtered
,被防火墙阻塞。作为一个普通的 Linux 管理员,这是你大部分时间会做的扫描类型之一。
-sS
扫描显示 TCP 端口的状态,但不显示 UDP 端口的状态。要查看 UDP 端口,使用-sU
选项:
donnie@linux-0ro8:~> sudo nmap -sU 192.168.0.37
Starting Nmap 6.47 ( http://nmap.org ) at 2017-12-28 12:41 EST
Nmap scan report for 192.168.0.37
Host is up (0.00018s latency).
Not shown: 996 closed ports
PORT STATE SERVICE
123/udp open ntp
631/udp open|filtered ipp
3283/udp open|filtered netassistant
5353/udp open zeroconf
MAC Address: 00:0A:95:8B:E0:C0 (Apple)
Nmap done: 1 IP address (1 host up) scanned in 119.91 seconds
donnie@linux-0ro8:~>
在这里,你看到了一些不同的东西。你看到两个端口被列为open|filtered
。这是因为由于 UDP 端口对 Nmap 扫描的响应方式,Nmap 并不能总是确定 UDP 端口是open
还是filtered
。在这种情况下,我们知道这两个端口可能是打开的,因为我们已经看到它们对应的 TCP 端口是打开的。
ACK 数据包扫描也可能是有用的,但不是为了查看目标机器的网络服务状态。相反,它是一个很好的选项,当你需要查看是否有防火墙阻挡你和目标机器之间的通路时。ACK 扫描命令看起来像这样:
sudo nmap -sA 192.168.0.37
你不仅限于一次只扫描一台机器。你可以一次扫描一组机器或整个子网:
sudo nmap -sS 192.168.0.1-128
sudo nmap -sS 192.168.0.0/24
第一个命令只扫描了这个网络段上的前 128 个主机。第二个命令扫描了使用 24 位子网掩码的子网上的所有 254 个主机。
发现扫描对于只想看看网络上有哪些设备是有用的:
sudo nmap -sn 192.168.0.0/24
使用-sn
选项,Nmap 将首先检测您是在扫描本地子网还是远程子网。如果子网是本地的,Nmap 将发送一个地址解析协议(ARP)广播,请求子网上每个设备的 IPv4 地址。这是一种可靠的发现设备的方式,因为 ARP 不会被设备的防火墙阻止。然而,ARP 广播无法跨越路由器,这意味着您无法使用 ARP 来发现远程子网上的主机。因此,如果 Nmap 检测到您正在对远程子网进行发现扫描,它将发送 ping 数据包而不是 ARP 广播。使用 ping 数据包进行发现不像使用 ARP 那样可靠,因为一些网络设备可以配置为忽略 ping 数据包。无论如何,这是我自己家庭网络的一个例子:
donnie@linux-0ro8:~> sudo nmap -sn 192.168.0.0/24
Starting Nmap 6.47 ( http://nmap.org ) at 2017-12-25 14:48 EST
Nmap scan report for 192.168.0.1
Host is up (0.00043s latency).
MAC Address: 00:18:01:02:3A:57 (Actiontec Electronics)
Nmap scan report for 192.168.0.3
Host is up (0.0044s latency).
MAC Address: 44:E4:D9:34:34:80 (Cisco Systems)
Nmap scan report for 192.168.0.5
Host is up (0.00026s latency).
MAC Address: 1C:1B:0D:0A:2A:76 (Unknown)
Nmap scan report for 192.168.0.6
Host is up (0.00013s latency).
MAC Address: 90:B1:1C:A3:DF:5D (Dell)
. . .
. . .
我们在这段代码中看到了四个主机,每个主机有三行输出。第一行显示 IP 地址,第二行显示主机是否在线,第三行显示主机网络适配器的 MAC 地址。每个 MAC 地址的前三对字符表示该网络适配器的制造商。(记录上,未知的网络适配器是最近型号的技嘉主板上的。我不知道为什么它不在 Nmap 数据库中。)
我们将要看的最后一个扫描为我们做了四件事:
-
它识别
open
、closed
和filtered
的 TCP 端口 -
它识别正在运行的服务的版本
-
它运行一组随 Nmap 提供的漏洞扫描脚本
-
它试图识别目标主机的操作系统
执行所有这些操作的扫描命令如下:
sudo nmap -A 192.168.0.37
我猜您可以将-A
选项看作是all选项,因为它确实做了所有的事情。(嗯,几乎所有,因为它不扫描 UDP 端口。)这是我针对目标进行的扫描的结果:
donnie@linux-0ro8:~> sudo nmap -A 192.168.0.37
Starting Nmap 6.47 ( http://nmap.org ) at 2017-12-24 19:33 EST
Nmap scan report for 192.168.0.37
Host is up (0.00016s latency).
Not shown: 996 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.1 (protocol 1.99)
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
|_sshv1: Server supports SSHv1
515/tcp open printer?
631/tcp open ipp CUPS 1.1
| http-methods: Potentially risky methods: PUT
|_See http://nmap.org/nsedoc/scripts/http-methods.html
| http-robots.txt: 1 disallowed entry
|_/
|_http-title: Common UNIX Printing System
5900/tcp open vnc Apple remote desktop vnc
| vnc-info:
| Protocol version: 3.889
| Security types:
|_ Mac OS X security type (30)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at http://www.insecure.org/cgi-bin/servicefp-submit.cgi :
SF-Port515-TCP:V=6.47%I=7%D=12/24%Time=5A40479E%P=x86_64-suse-linux-gnu%r(
SF:GetRequest,1,"\x01");
MAC Address: 00:0A:95:8B:E0:C0 (Apple)
Device type: general purpose
Running: Apple Mac OS X 10.4.X
OS CPE: cpe:/o:apple:mac_os_x:10.4.10
OS details: Apple Mac OS X 10.4.10 - 10.4.11 (Tiger) (Darwin 8.10.0 - 8.11.1)
Network Distance: 1 hop
Service Info: OS: Mac OS X; CPE: cpe:/o:apple:mac_os_x
TRACEROUTE
HOP RTT ADDRESS
1 0.16 ms 192.168.0.37
OS and Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 213.92 seconds
donnie@linux-0ro8:~>
这里有几件有趣的事情。首先是安全外壳信息:
22/tcp open ssh OpenSSH 5.1 (protocol 1.99)
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
|_sshv1: Server supports SSHv1
版本 5.1 是一个非常古老的 OpenSSH 版本。(在撰写本文时,当前版本是 7.6。)更糟糕的是,这个 OpenSSH 服务器支持安全外壳协议的第一个版本。第一个版本存在严重缺陷,很容易被利用,所以您绝不希望在您的网络上看到这个。
接下来,我们对使用 OpenVAS 扫描发现的打印服务漏洞进行了详细说明:
515/tcp open printer?
631/tcp open ipp CUPS 1.1
| http-methods: Potentially risky methods: PUT
|_See http://nmap.org/nsedoc/scripts/http-methods.html
| http-robots.txt: 1 disallowed entry
|_/
|_http-title: Common UNIX Printing System
在631/tcp
行中,我们看到相关服务是ipp
,代表Internet Printing Protocol。这个协议基于我们用来查看网页的超文本传输协议(HTTP)。HTTP 用于从客户端向服务器发送数据的两种方法是POST和PUT。我们真正希望的是每个 HTTP 服务器都使用 POST 方法,因为 PUT 方法使得有人通过操纵 URL 很容易就能破坏服务器。因此,如果您扫描一个服务器并发现它允许使用 PUT 方法进行任何类型的 HTTP 通信,那么您就有了一个潜在的问题。在这种情况下,解决方案将是更新操作系统,并希望更新修复问题。如果这是一个 Web 服务器,您会想与 Web 服务器管理员交谈,让他们知道您发现了什么。
最后,让我们看看 Nmap 发现的目标机器的操作系统信息:
Running: Apple Mac OS X 10.4.X
OS CPE: cpe:/o:apple:mac_os_x:10.4.10
OS details: Apple Mac OS X 10.4.10 - 10.4.11 (Tiger) (Darwin 8.10.0 - 8.11.1)
Network Distance: 1 hop
Service Info: OS: Mac OS X; CPE: cpe:/o:apple:mac_os_x
等等,什么?Mac OS X 10.4?那不是非常古老吗?是的,确实如此。在过去的几章中我一直保密的秘密是,我 OpenVAS 和 Nmap 扫描演示的目标机器是我 2003 年的古老的、收藏价值的苹果 eMac。我想扫描它会给我们一些有趣的结果看,看来我是对的。(是的,是 eMac,不是 iMac。)
保护 GRUB 2 引导加载程序的密码
有时人们会忘记密码,即使他们是管理员。有时,人们购买了二手电脑,但忘记询问卖家密码是什么。(是的,我曾经这样做过。)不过,这没关系,因为所有主要操作系统都有办法让您重置或恢复丢失的管理员密码。这很方便,但是当有人可以物理访问机器时,登录密码的整个概念似乎就没有什么意义了。假设您的笔记本电脑刚刚被盗。如果您没有加密硬盘,窃贼只需要几分钟就可以重置密码并窃取您的数据。如果您已经加密了硬盘,保护级别将取决于您使用的操作系统。使用标准的 Windows 文件夹加密,窃贼可以通过重置密码来访问加密文件夹。在 Linux 机器上使用 LUKS 整盘加密,窃贼将无法绕过输入加密密码的步骤。
在 Linux 中,我们有一种方法来防止未经授权的密码重置,即使我们没有使用整盘加密。我们所要做的就是对Grand Unified Bootloader (GRUB)进行密码保护,这将阻止窃贼进入紧急模式进行密码重置。
无论您是否需要本节中的建议取决于您组织的物理安全设置。这是因为将 Linux 机器引导到紧急模式需要物理访问该机器。这不是您可以远程执行的操作。在具有适当物理安全措施的组织中,服务器,尤其是保存敏感数据的服务器,都被锁在一个房间里,而这个房间又被锁在另一个房间里。只有极少数信任的人被允许进入,并且他们必须在两个访问点出示自己的凭据。因此,在这些服务器的引导加载程序上设置密码将是毫无意义的,除非您正在处理一个规定不同的监管机构。
另一方面,对于摆放在公开场所的工作站和笔记本电脑的引导加载程序进行密码保护可能非常有用。但是,仅仅这样做并不能保护您的数据。某人仍然可以从活动光盘或 USB 存储设备引导机器,挂载机器的硬盘,并获取敏感数据。这就是为什么您还需要加密您的敏感数据,就像我在第四章中向您展示的那样,加密和 SSH 加固。
要重置密码,您所要做的就是在引导菜单出现时中断引导过程,并更改一些内核参数。然而,重置密码并不是您可以从引导菜单中做的唯一事情。如果您的机器安装了多个操作系统,例如一个分区上安装了 Windows,另一个分区上安装了 Linux,引导菜单允许您选择要引导的操作系统。使用旧式的传统 GRUB,您可以防止人们编辑内核参数,但无法阻止他们选择多重引导机器上的另一个操作系统。在较新版本的 Linux 中使用的新 GRUB 2 中,您可以选择您希望能够从任何特定操作系统引导的用户。
现在,为了让您知道我所说的您可以从 GRUB 2 引导菜单中编辑内核参数,让我向您展示如何执行密码重置。
重置 Red Hat/CentOS 的密码
当引导菜单出现时,按下箭头键一次中断引导过程。然后,按上箭头键一次选择默认的引导选项:
按下E键编辑内核参数。当 GRUB 2 配置出现时,光标下移,直到看到这一行:
从此行中删除rhgb quiet
,然后在行末添加rd.break enforcing=0
。以下是这两个新选项为您做的事情:
-
rd.break
:这将导致机器进入紧急模式,从而使您无需输入 root 用户密码即可获得 root 用户特权。即使 root 用户密码尚未设置,这仍然有效。 -
enforcing=0
:在启用 SELinux 的系统上重置密码时,/etc/shadow
文件的安全上下文将更改为错误类型。如果系统在执行模式下执行此操作,SELinux 将阻止您登录,直到shadow
文件重新标记。但是,在引导过程中重新标记可能需要很长时间,特别是对于大容量驱动器。通过将 SELinux 设置为宽松模式,您可以等到重启后再恢复shadow
文件的正确安全上下文。
编辑内核参数后,按下Ctrl + X继续引导过程。这将带您到带有switch_root
命令提示符的紧急模式:
在紧急模式下,文件系统以只读方式挂载。您需要将其重新挂载为读写模式,并在重置密码之前进入chroot
模式:
mount -o remount,rw /sysroot
chroot /sysroot
输入这两个命令后,命令提示符将更改为普通的 bash shell:
现在您已经到达这个阶段,终于可以重置密码了。
如果要重置 root 用户密码,甚至是在以前不存在密码的情况下创建 root 密码,只需输入:
passwd
然后,输入新的所需密码。
如果系统从未设置过 root 用户密码,而您仍然不希望设置密码,您可以重置具有完整 sudo 特权的帐户的密码。例如,在我的系统上,命令如下:
passwd donnie
接下来,将文件系统重新挂载为只读。然后,输入两次exit
以恢复重启:
mount -o remount,ro /
exit
exit
重启后,您需要做的第一件事是恢复/etc/shadow
文件的正确 SELinux 安全上下文。然后,将 SELinux 恢复为强制模式:
sudo restorecon /etc/shadow
sudo setenforce 1
这是我shadow
文件上下文设置的之前和之后的屏幕截图:
您可以看到重置密码将文件类型更改为unlabeled_t
。运行restorecon
命令将类型更改回shadow_t
。
在 Ubuntu 上重置密码
在 Ubuntu 系统上重置密码的过程有很大不同,也更简单。首先,按下向下箭头键一次以中断引导过程,然后按一次向上箭头键以选择默认引导选项。按下E键编辑内核参数:
当 GRUB 2 配置出现时,光标下移,直到看到linux
行:
将ro
更改为rw
并添加init=/bin/bash
:
按下Ctrl + X继续引导。这将带您到一个 root shell:
由于 Ubuntu 通常不会为 root 用户分配密码,因此您很可能只会重置具有完整 sudo 特权的用户的密码。请参阅以下示例:
passwd donnie
在此模式下,常规的重启命令将无效。因此,在完成密码重置操作后,输入以下命令进行重启:
exec /sbin/init
机器现在将正常启动。
在 Red Hat/CentOS 上防止内核参数编辑
自从引入 Red Hat/CentOS 7.2 以来,设置 GRUB 2 密码以防止内核参数编辑变得很容易。您只需运行一个命令并选择一个密码:
[donnie@localhost ~]$ sudo grub2-setpassword
[sudo] password for donnie:
Enter password:
Confirm password:
[donnie@localhost ~]$
就是这样。密码哈希将存储在/boot/grub2/user.cfg
文件中。
现在,当您重新启动机器并尝试编辑内核参数时,您将被提示输入用户名和密码:
请注意,即使系统上尚未设置 root 用户的密码,您也将输入root
作为用户名。在这种情况下,root
用户只是 GRUB 2 的超级用户。
防止在 Ubuntu 上编辑内核参数
Ubuntu 没有 Red Hat 和 CentOS 拥有的那种很酷的实用程序,因此您必须手动编辑配置文件来设置 GRUB 2 密码。
在/etc/grub.d/
目录中,您将看到组成 GRUB 2 配置的文件:
donnie@ubuntu3:/etc/grub.d$ ls -l
total 76
-rwxr-xr-x 1 root root 9791 Oct 12 16:48 00_header
-rwxr-xr-x 1 root root 6258 Mar 15 2016 05_debian_theme
-rwxr-xr-x 1 root root 12512 Oct 12 16:48 10_linux
-rwxr-xr-x 1 root root 11082 Oct 12 16:48 20_linux_xen
-rwxr-xr-x 1 root root 11692 Oct 12 16:48 30_os-prober
-rwxr-xr-x 1 root root 1418 Oct 12 16:48 30_uefi-firmware
-rwxr-xr-x 1 root root 214 Oct 12 16:48 40_custom
-rwxr-xr-x 1 root root 216 Oct 12 16:48 41_custom
-rw-r--r-- 1 root root 483 Oct 12 16:48 README
donnie@ubuntu3:/etc/grub.d$
您要编辑的文件是40_custom
文件。但是,在编辑文件之前,您需要使用grub-mkpasswd-pbkdf2
实用程序创建密码哈希。:
donnie@ubuntu3:/etc/grub.d$ grub-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.F1BA16B2799CBF6A6DFBA537D43222A0D5006124ECFEB29F5C81C9769C6C3A66BF53C2B3AB71BEA784D4386E86C991F7B5D33CB6C29EB6AA12C8D11E0FFA0D40.371648A84CC4131C3CFFB53604ECCBA46DA75AF196E970C98483385B0BE026590C63A1BAC23691517BC4A5D3EDF89D026B599A0D3C49F2FB666F9C12B56DB35D
donnie@ubuntu3:/etc/grub.d$
在您喜欢的编辑器中打开40_custom
文件,并添加一行来定义超级用户是谁。再添加一行密码哈希。在我的情况下,文件现在看起来像这样:
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
set superusers="donnie"
password_pbkdf2 donnie grub.pbkdf2.sha512.10000.F1BA16B2799CBF6A6DFBA537D43222A0D5006124ECFEB29F5C81C9769C6C3A66BF53C2B3AB71BEA784D4386E86C991F7B5D33CB6C29EB6AA12C8D11E0FFA0D40.371648A84CC4131C3CFFB53604ECCBA46DA75AF196E970C98483385B0BE026590C63A1BAC23691517BC4A5D3EDF89D026B599A0D3C49F2FB666F9C12B56DB35D
以password_pbkdf2
开头的文本字符串是一页上环绕的一行。
保存文件后,最后一步是生成新的grub.cfg
文件:
donnie@ubuntu3:/etc/grub.d$ sudo update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.4.0-104-generic
Found initrd image: /boot/initrd.img-4.4.0-104-generic
Found linux image: /boot/vmlinuz-4.4.0-101-generic
Found initrd image: /boot/initrd.img-4.4.0-101-generic
Found linux image: /boot/vmlinuz-4.4.0-98-generic
Found initrd image: /boot/initrd.img-4.4.0-98-generic
done
donnie@ubuntu3:/etc/grub.d$
现在,当我重新启动这台机器时,我必须输入密码才能编辑内核参数:
这只有一个问题。这不仅阻止除超级用户之外的任何人编辑内核参数,还阻止除超级用户之外的任何人正常启动。是的,没错。即使是正常启动,Ubuntu 现在也需要您输入授权超级用户的用户名和密码。修复很容易,尽管一点也不优雅。
修复需要在/boot/grub/grub.cfg
文件中插入一个单词。很容易,对吧?但是,这不是一个优雅的解决方案,因为您实际上不应该手动编辑grub.cfg
文件。在文件顶部,我们看到这样的内容:
# DO NOT EDIT THIS FILE
#
# It is automatically generated by grub-mkconfig using templates
# from /etc/grub.d and settings from /etc/default/grub
#
这意味着每当我们做一些会更新grub.cfg
文件的操作时,我们对文件所做的手动编辑都将丢失。这包括当我们进行安装新内核的系统更新,或者当我们运行sudo apt autoremove
删除不再需要的旧内核时。然而,最讽刺的是,官方的 GRUB 2 文档告诉我们手动编辑grub.cfg
文件来处理这些问题。
无论如何,为了修复这个问题,使您不再需要输入密码来正常启动,请在您喜欢的文本编辑器中打开/boot/grub/grub.cfg
文件。查找以menuentry
开头的第一行,应该看起来像这样:
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-f0f002e8-16b2-45a1-bebc-41e518ab9497' {
在该行的末尾的左花括号之前,添加文本字符串--unrestricted
。现在menuentry
应该看起来像这样:
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-f0f002e8-16b2-45a1-bebc-41e518ab9497' --unrestricted {
保存文件并通过重新启动机器进行测试。您应该看到机器现在会正常启动默认的启动选项。但是,您还会看到访问 Ubuntu 高级选项子菜单仍然需要密码。我们稍后会解决这个问题。
保护密码启动选项
对于任何给定的 Linux 系统,您至少会有两个启动选项。您将有正常启动和恢复模式启动的选项。红帽类型和 Ubuntu 类型的操作系统是独特的,因为当您进行操作系统更新时,它们不会覆盖旧内核。相反,它们会安装新内核以及旧内核,并且所有安装的内核都有自己的启动菜单条目。在红帽类型的系统上,您永远不会安装超过五个内核,因为一旦安装了五个内核,下次系统更新时最旧的内核将自动被删除。对于 Ubuntu 类型的系统,您需要通过运行sudo apt autoremove
手动删除旧内核。
你可能还有一个双重引导或多重引导配置,并且你可能只希望某些用户使用某些引导选项。假设你的系统上安装了 Windows 和 Linux,并且你希望阻止某些用户引导到其中一个。你可以通过配置 GRUB 2 来做到这一点,但你可能不会。我的意思是,无论如何登录操作系统都需要密码和用户帐户,那么为什么要麻烦呢?
我能想到的最现实的情景是,如果你在一个公共可访问的信息亭上设置了一台计算机。你肯定不希望普通公众将机器引导到恢复模式,这种技术将有助于防止这种情况发生。
这种技术在红帽类型和 Ubuntu 类型的发行版上基本相同,只有少数例外。最主要的例外是我们需要在 Ubuntu 机器上禁用子菜单。
禁用 Ubuntu 的子菜单
理论上,你可以通过将GRUB_DISABLE_SUBMENU=true
放入/etc/default/grub
文件中,然后运行sudo update-grub
来禁用 Ubuntu 子菜单。然而,我无法让它起作用,根据我的 DuckDuckGo 搜索结果,其他人也无法。因此,我们将手动编辑/boot/grub/grub.cfg
文件来修复它。
查找出现在第一个menuentry
项后面的submenu
行。它应该看起来像这样:
submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-f0f002e8-16b2-45a1-bebc-41e518ab9497' {
将该行注释掉,使其看起来像这样:
# submenu 'Advanced options for Ubuntu' $menuentry_id_option 'gnulinux-advanced-f0f002e8-16b2-45a1-bebc-41e518ab9497' {
向下滚动,直到你看到这行:
### END /etc/grub.d/10_linux ###
就在这行上面,你会看到子菜单段的闭合大括号。注释掉这个大括号,使其看起来像这样:
# }
现在当你重新启动机器时,你将看到整个引导选项列表,而不仅仅是默认的引导选项和一个子菜单。然而,按目前的情况,只有指定的超级用户才能引导到除默认选项以外的任何东西。
保护引导选项的步骤,适用于 Ubuntu 和 Red Hat。
从这里开始,对于 CentOS 和 Ubuntu 虚拟机,步骤都是一样的,除了以下几点:
-
在你的 Ubuntu 机器上,
grub.cfg
文件在/boot/grub/
目录中。在你的 CentOS 机器上,它在/boot/grub2/
目录中。 -
在 Ubuntu 上,
/boot/grub/
和/etc/grub.d/
目录是可读的。因此,你可以像普通用户一样进入它们。 -
在 CentOS 上,
/boot/grub2/
和/etc/grub.d/
目录只对 root 用户有限制。因此,要进入这些目录,你需要登录到 root 用户的 shell。或者,你可以在你的普通用户 shell 中使用sudo ls -l
列出内容,并使用sudo vim /boot/grub2/grub.cfg
或sudo vim /etc/grub.d/40_custom
编辑你需要编辑的文件。(用你喜欢的编辑器替换 vim。) -
在 Ubuntu 上,创建密码哈希的命令是
grub-mkpasswd-pbkdf2
。在 CentOS 上,命令是grub2-mkpasswd-pbkdf2
。
考虑到这些细微差别,让我们开始吧。
如果你正在使用只有文本模式界面的服务器,你肯定会想从具有图形界面的工作站远程登录。如果你的工作站正在运行 Windows,你可以使用 Cygwin,就像我在第一章中向你展示的那样,在虚拟环境中运行 Linux。
这是因为你需要一种方法来复制和粘贴密码哈希到你需要编辑的两个文件中。
你要做的第一件事是为你的新用户创建一个密码哈希:
- 在 Ubuntu 上:
grub-mkpasswd-pbkdf2
- 在 CentOS 上:
grub2-mkpasswd-pbkdf2
接下来,打开你的文本编辑器中的/etc/grub.d/40_custom
文件,并为你的新用户添加一行,以及你刚刚创建的密码哈希。该行应该看起来像这样:
password_pbkdf2 goldie grub.pbkdf2.sha512.10000.225205CBA2584240624D077ACB84E86C70349BBC00DF40A219F88E5691FB222DD6E2F7765E96C63C4A8FA3B41BDBF62DA1F3B07C700D78BC5DE524DCAD9DD88B.9655985015C3BEF29A7B8E0A6EA42599B1152580251FF99AA61FE68C1C1209ACDCBBBDAA7A97D4FC4DA6984504923E1449253024619A82A57CECB1DCDEE53C06
请注意,这是一页上环绕的一行。
接下来您应该运行一个实用程序,该实用程序将读取/etc/grub.d/
目录中的所有文件以及/etc/default/grub
文件,然后重新构建grub.cfg
文件。但是,在 CentOS 上,该实用程序无法正常工作。在 Ubuntu 上,它可以正常工作,但它将覆盖您可能已经对grub.cfg
文件进行的任何更改。因此,我们将采取欺骗手段。
在文本编辑器中打开grub.cfg
文件:
- 在 Ubuntu 上:
sudo vim /boot/grub/grub.cfg
- 在 CentOS 上:
sudo vim /boot/grub2/grub.cfg
向下滚动直到看到### BEGIN /etc/grub.d/40_custom ###
部分。在此部分,复制并粘贴刚刚添加到40_custom
文件的行。此部分现在应该看起来像这样:
### BEGIN /etc/grub.d/40_custom ###
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
password_pbkdf2 "goldie" grub.pbkdf2.sha512.10000.225205CBA2584240624D077ACB84E86C70349BBC00DF40A219F88E5691FB222DD6E2F7765E96C63C4A8FA3B41BDBF62DA1F3B07C700D78BC5DE524DCAD9DD88B.9655985015C3BEF29A7B8E0A6EA42599B1152580251FF99AA61FE68C1C1209ACDCBBBDAA7A97D4FC4DA6984504923E1449253024619A82A57CECB1DCDEE53C06
### END /etc/grub.d/40_custom ###
最后,您已经准备好为各个菜单项添加密码保护。在这里,我发现 Ubuntu 和 CentOS 之间又有一个不同之处。
在 CentOS 的所有菜单项中,您将看到--unrestricted
选项已经存在于所有菜单项中。这意味着默认情况下,所有用户都被允许启动每个菜单选项,即使您设置了超级用户密码:
menuentry 'CentOS Linux (3.10.0-693.11.1.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-693.el7.x86_64-advanced-f338b70d-ff57-404e-a349-6fd84ad1b692' {
因此,在 CentOS 上,如果您希望所有用户都能够使用所有可用的引导选项,则无需进行任何操作。
现在,假设您有一个menuentry
,您希望所有人都能访问。在 CentOS 上,就像我刚指出的那样,您无需做任何事情。在 Ubuntu 上,添加--unrestricted
到menuentry
,就像您之前所做的那样:
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-f0f002e8-16b2-45a1-bebc-41e518ab9497' --unrestricted {
如果您希望除超级用户之外没有其他用户能够从特定选项启动,请添加--users ""
。(在 CentOS 上,请务必首先删除--unrestricted
选项。)
menuentry 'Ubuntu, with Linux 4.4.0-98-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-98-generic-recovery-f0f002e8-16b2-45a1-bebc-41e518ab9497' --users "" {
如果您只希望超级用户和其他特定用户能够从某个选项启动,请添加--users
,后跟用户名。(同样,在 CentOS 上,首先删除--unrestricted
选项。):
menuentry 'Ubuntu, with Linux 4.4.0-97-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-97-generic-advanced-f0f002e8-16b2-45a1-bebc-41e518ab9497' --users goldie {
如果您有多个用户希望访问引导选项,请在### BEGIN /etc/grub.d/40_custom ###
部分为新用户添加条目。然后,将新用户添加到您希望其访问的menuentry
中。使用逗号分隔用户名:
menuentry 'Ubuntu, with Linux 4.4.0-97-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.4.0-97-generic-advanced-f0f002e8-16b2-45a1-bebc-41e518ab9497' --users goldie,frank {
保存文件并重新启动以尝试不同的选项。
既然我们已经做了这么多工作,我需要再次提醒您,您对grub.cfg
文件所做的任何手动编辑都将在生成新的grub.cfg
时丢失。因此,每当您进行包括安装或删除内核的系统更新时,您都需要手动编辑此文件,以重新添加密码保护。(事实上,我让您将用户及其密码添加到/etc/grub.d/40_custom
文件的唯一真正原因是,这样您将始终可以将该信息复制并粘贴到grub.cfg
中。)我希望有一种更加优雅的方法来做到这一点,但根据官方 GRUB 2 文档,这是不可能的。
您将在官方 GRUB 2 文档的安全部分找到www.gnu.org/software/grub/manual/grub/grub.html#Security
。
在我们离开这个话题之前,我想分享一下我对 GRUB 2 的个人看法。
由于旧的传统版本无法与新的基于 UEFI 的主板配合使用,因此有必要创建一个新版本的 GRUB。但是,GRUB 2 也有一些令人失望的地方。
首先,与传统的 GRUB 不同,GRUB 2 在所有 Linux 发行版上的实现并不一致。事实上,我们在演示中刚刚看到,当我们从 CentOS 切换到 Ubuntu 时,我们必须以不同的方式进行操作。
接下来是 GRUB 2 开发人员给我们提供了一些良好的安全选项,但他们并没有给我们提供一种优雅的实现方式。我是说,真的。通过手动编辑一个在每次操作系统更新时都会被覆盖的文件来实现安全功能的整个想法似乎并不正确。
最后,还有 GRUB 2 文档的可悲状态。我并不是要自吹自擂,因为我知道那是不合适的。然而,我认为可以肯定地说,这是你在任何地方找到的唯一全面的 GRUB 2 密码保护功能的写作。
安全配置 BIOS/UEFI
这个主题与我们迄今为止看到的任何内容都不同,因为它与操作系统无关。相反,我们现在要谈论的是计算机硬件。
每个计算机主板都有一个 BIOS 或 UEFI 芯片,它存储了计算机的硬件配置和启动引导指令,这些指令在打开电源后启动引导过程所需。UEFI 已经取代了较新主板上的老式 BIOS,并且它比老式 BIOS 具有更多的安全功能。
关于 BIOS/UEFI 设置,我无法给你任何具体的信息,因为每个主板型号的操作方式都不同。我可以给你一些更一般化的信息。
当你考虑 BIOS/UEFI 安全时,你可能会考虑禁用从除了正常系统驱动器以外的任何引导设备引导的能力。在下面的截图中,你可以看到我已经禁用了除了连接系统驱动器的 SATA 驱动器端口之外的所有 SATA 驱动器端口:
当计算机放在公众可以轻易物理接触的地方时,这可能需要考虑。对于被锁在安全房间并且访问受限的服务器,除非某个监管机构的安全要求另有规定,否则没有真正的理由担心。对于放在公开场所的机器,整个磁盘加密可以防止有人在从光盘或 USB 设备引导后窃取数据。然而,你可能仍有其他原因阻止任何人从这些备用引导设备引导机器。
另一个考虑因素可能是,如果你在处理超敏感数据的安全环境中工作。如果你担心未经授权的敏感数据外泄,你可能考虑禁用写入 USB 设备的能力。这也将阻止人们从 USB 设备引导机器:
然而,BIOS/UEFI 安全不仅仅是这些。今天的现代服务器 CPU 配备了各种安全功能,以帮助防止数据泄露。例如,让我们看一下实现在 Intel Xeon CPU 中的安全功能清单:
-
身份保护技术
-
高级加密标准新指令
-
可信执行技术
-
硬件辅助虚拟化技术
AMD,在 CPU 市场上的勇敢的小角色,他们在他们的新一代 EPYC 服务器 CPU 中有自己的新安全功能。这些功能包括:
-
安全内存加密
-
安全加密虚拟化
无论如何,你都会在服务器的 UEFI 设置实用程序中配置这些 CPU 安全选项。
你可以在www.intel.com/content/www/us/en/data-security/security-overview-general-technology.html
上阅读关于 Intel Xeon 安全功能的信息。
而且,你可以在semiaccurate.com/2017/06/22/amds-epyc-major-advance-security/
上阅读关于 AMD EPYC 安全功能的信息。
当然,对于任何放在公开场所的机器,密码保护 BIOS 或 UEFI 是个好主意:
即使没有其他原因,也要这样做以防止人们对你的设置进行篡改。
使用系统设置的安全检查表
我之前告诉过您 OpenSCAP,这是一个非常有用的工具,可以通过最少的努力来锁定您的系统。OpenSCAP 带有各种配置文件,您可以应用这些配置文件来帮助使您的系统符合不同监管机构的标准。但是,OpenSCAP 无法为您做某些事情。例如,某些监管机构要求您的服务器硬盘以特定方式分区,将某些目录分隔到自己的分区中。如果您已经将服务器设置为一个大分区下的所有内容,您无法通过使用 OpenSCAP 的修复程序来解决这个问题。确保服务器符合任何适用安全法规的程序必须在安装操作系统之前开始。为此,您需要适当的清单。
如果您只需要通用安全清单,有几个地方可以获取。德克萨斯大学奥斯汀分校发布了适用于 Red Hat Enterprise 7 的通用清单,您可以根据需要将其调整为适用于 CentOS 7、Oracle Linux 7 或 Scientific Linux 7。您可能会发现某些清单项目不适用于您的情况,您可以根据需要进行调整:
对于特定的业务领域,您需要从适用的监管机构获取清单。如果您在金融领域工作或与接受信用卡支付的企业合作,您将需要来自支付卡行业安全标准委员会的清单:
而对于美国的医疗保健机构,有其要求的 HIPAA。对于美国的上市公司,有其要求的萨班斯-奥克斯利法:
您可以在以下网址获取德克萨斯大学的清单:wikis.utexas.edu/display/ISO/Operating+System+Hardening+Checklists
。
您可以在以下网址获取 PCI-DSS 清单:www.pcisecuritystandards.org/
.
您可以在以下网址获取 HIPAA 清单:www.hipaainstitute.com/security-checklist.
而且,您可以在以下网址获取萨班斯-奥克斯利清单:www.sarbanes-oxley-101.com/sarbanes-oxley-checklist.htm
。
其他监管机构可能也有他们自己的清单。如果您知道您必须处理其中任何一个,请务必获取适当的清单。
摘要
再次,我们已经结束了另一个章节,并涵盖了许多有趣的话题。我们首先看了一些审计系统上运行的各种服务的方法,并看到了一些您可能不想看到的示例。然后,我们看到了如何使用 GRUB 2 的密码保护功能,以及在使用这些功能时我们必须处理的一些小问题。接下来,我们通过正确设置系统的 BIOS/UEFI 来改变步调,进一步锁定系统。最后,我们看了为什么我们需要通过获取和遵循适当的清单来正确开始准备建立一个强化系统。
这不仅结束了另一个章节,也结束了这本书。但是,这并不意味着您在掌握 Linux 安全和强化的旅程结束了。当您继续这个旅程时,您会发现还有更多需要学习的内容,还有更多内容无法适应 300 页书的范围。您未来的方向主要取决于您所在的 IT 管理领域。不同类型的 Linux 服务器,无论是 Web 服务器、DNS 服务器还是其他类型,都有自己特殊的安全要求,您将希望按照最适合您需求的学习路径。
我很享受能够陪伴你一起走过的旅程。希望你和我一样享受这段旅程。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!