# pw lock imani
第 16 章 安全性
目录
16.1. 概述
关于如何保护系统和网络,已经编写了数百种标准做法,作为 FreeBSD 用户,了解如何防范攻击和入侵者是必须的。
本章将讨论一些基本原理和技术。FreeBSD 系统自带多层安全机制,还可以添加许多第三方实用程序来增强安全性。
本章涵盖以下内容:
FreeBSD 系统安全的基本概念。
FreeBSD 中可用的各种加密机制。
如何配置 TCP Wrappers 以与 inetd(8) 一起使用。
如何在 FreeBSD 上设置 Kerberos。
如何在 FreeBSD 上配置和使用 OpenSSH。
如何在 FreeBSD 上使用 OpenSSL。
如何使用文件系统 ACL。
如何使用 pkg 审核从 Ports Collection 安装的第三方软件包。
如何利用 FreeBSD 安全公告。
什么是进程会计以及如何在 FreeBSD 上启用它。
如何使用登录类或资源限制数据库来控制用户资源。
什么是 Capsicum 以及一个基本示例。
由于某些主题过于复杂,因此会在专门的章节中进行介绍,例如 防火墙、强制访问控制 以及 VPN over IPsec 等文章。
16.2. 简介
安全是每个人的责任。任何系统中的薄弱环节都可能允许入侵者访问关键信息,并对整个网络造成破坏。信息安全的核心原则之一是 CIA 三元组,它代表信息系统的机密性、完整性和可用性。
CIA 三元组是计算机安全的基础概念,因为客户和用户期望他们的数据得到保护。例如,客户期望他们的信用卡信息得到安全存储(机密性)、他们的订单不会在后台被修改(完整性)以及他们随时可以访问他们的订单信息(可用性)。
为了提供 CIA,安全专业人员会采用纵深防御策略。纵深防御的理念是在多个层面上添加安全措施,以防止单一层面失效,进而导致整个安全系统崩溃。例如,系统管理员不能仅仅打开防火墙就认为网络或系统是安全的。还必须审核帐户、检查二进制文件的完整性并确保没有安装恶意工具。为了实施有效的安全策略,必须了解威胁以及如何防御这些威胁。
在计算机安全方面,什么是威胁?威胁不仅仅包括来自远程位置试图未经许可访问系统的远程攻击者。威胁还包括员工、恶意软件、未经授权的网络设备、自然灾害、安全漏洞,甚至竞争对手。
系统和网络可能在未经许可的情况下被访问,有时是意外的,有时是远程攻击者所为,在某些情况下,则是通过企业间谍活动或前雇员所为。作为用户,重要的是要为安全漏洞做好准备,并在发生错误导致安全漏洞时承认错误,并向安全团队报告可能存在的问题。作为管理员,重要的是了解威胁并准备好减轻这些威胁。
在将安全应用于系统时,建议从保护基本帐户和系统配置开始,然后保护网络层,使其符合系统策略和组织的安全流程。许多组织已经制定了涵盖技术设备配置的安全策略。该策略应包括工作站、台式机、移动设备、电话、生产服务器和开发服务器的安全配置。在许多情况下,标准操作程序 (SOP) 已经存在。如果有疑问,请咨询安全团队。
16.3. 保护帐户
在 FreeBSD 中维护安全的帐户对于数据的机密性、系统完整性和权限分离至关重要,因为它可以防止未经授权的访问、恶意软件和数据泄露,同时确保合规性并保护组织的声誉。
16.3.1. 阻止登录
在保护系统时,一个好的起点是对帐户进行审计。禁用任何不需要登录访问权限的帐户。
确保 |
要拒绝帐户的登录访问权限,存在两种方法。
第一个方法是锁定帐户,此示例显示如何锁定 imani
帐户
第二种方法是通过将 shell 更改为 /usr/sbin/nologin 来阻止登录访问权限。当用户尝试登录时,nologin(8) shell 会阻止系统为用户分配 shell。
只有超级用户可以更改其他用户的 shell
# chsh -s /usr/sbin/nologin imani
16.3.2. 密码哈希
密码是技术的必要之恶。当必须使用密码时,密码应该复杂,并且应该使用强大的哈希机制来加密存储在密码数据库中的版本。FreeBSD 在其 crypt()
库中支持多种算法,包括 SHA256、SHA512 和 Blowfish 哈希算法,有关详细信息,请参阅 crypt(3)。
不应该将 SHA512 的默认值更改为安全性较低的哈希算法,但可以更改为安全性更高的 Blowfish 算法。
Blowfish 不属于 AES,也不被认为符合任何联邦信息处理标准 (FIPS)。在某些环境中可能不允许使用它。 |
要确定使用哪种哈希算法来加密用户的密码,超级用户可以在 FreeBSD 密码数据库中查看用户的哈希值。每个哈希值都以一个符号开头,该符号指示用于加密密码的哈希机制类型。
如果使用 DES,则没有开始符号。对于 MD5,符号是 $
。对于 SHA256 和 SHA512,符号是 $6$
。对于 Blowfish,符号是 $2a$
。在此示例中,imani
的密码使用默认的 SHA512 算法进行哈希处理,因为哈希以 $6$
开头。请注意,加密后的哈希值(而不是密码本身)存储在密码数据库中
# grep imani /etc/master.passwd
输出应类似于以下内容
imani:$6$pzIjSvCAn.PBYQBA$PXpSeWPx3g5kscj3IMiM7tUEUSPmGexxta.8Lt9TGSi2lNQqYGKszsBPuGME0:1001:1001::0:0:imani:/usr/home/imani:/bin/sh
哈希机制是在用户的登录类中设置的。
可以使用以下命令来检查当前使用的哈希机制
# grep user /etc/master.passwd
输出应类似于以下内容
:passwd_format=sha512:\
例如,要将算法更改为 Blowfish,请将该行修改为以下内容
:passwd_format=blf:\
然后,必须执行 cap_mkdb(1) 来升级 login.conf 数据库
# cap_mkdb /etc/login.conf
请注意,此更改不会影响任何现有的密码哈希值。这意味着所有密码都应该通过要求用户运行 passwd
来更改密码以重新哈希。
16.3.3. 密码策略实施
对本地帐户实施强密码策略是系统安全的基本方面。在 FreeBSD 中,密码长度、密码强度和密码复杂性可以使用内置的可插拔身份验证模块 (PAM) 来实施。
本节演示如何使用 pam_passwdqc(8) 模块来配置最小和最大密码长度以及混合字符的强制执行。当用户更改密码时,会强制执行此模块。
要配置此模块,请成为超级用户,并在 /etc/pam.d/passwd 中取消包含 pam_passwdqc.so
的行的注释。
然后,编辑该行以匹配密码策略
password requisite pam_passwdqc.so min=disabled,disabled,disabled,12,10 similar=deny retry=3 enforce=users
参数的解释可以在 pam_passwdqc(8) 中找到。
保存此文件后,更改密码的用户将看到类似于以下内容的消息
% passwd
输出应类似于以下内容
Changing local password for user Old Password: You can now choose the new password. A valid password should be a mix of upper and lower case letters, digits and other characters. You can use a 12 character long password with characters from at least 3 of these 4 classes, or a 10 character long password containing characters from all the classes. Characters that form a common pattern are discarded by the check. Alternatively, if no one else can see your terminal now, you can pick this as your password: "trait-useful&knob". Enter new password:
如果输入的密码与策略不匹配,则会将其拒绝并显示警告,用户将有机会尝试再次输入密码,最多可以尝试配置的重试次数。
如果您的组织的策略要求密码过期,则 FreeBSD 支持 /etc/login.conf 中用户登录类中的 passwordtime
default
登录类包含一个示例
# :passwordtime=90d:\
因此,要将此登录类的过期时间设置为 90 天,请删除注释符号 (#),保存编辑,然后执行以下命令
# cap_mkdb /etc/login.conf
要将过期时间设置为单个用户,请将过期日期或过期天数以及用户名传递给 pw
# pw usermod -p 30-apr-2025 -n user
如这里所示,过期日期以日、月和年的形式设置。有关更多信息,请参阅 pw(8)。
16.3.4. 使用 sudo 共享管理
系统管理员通常需要能够向用户授予增强权限,以便他们可以执行特权任务。团队成员被授予访问 FreeBSD 系统以执行其特定任务的权限,这给每个管理员带来了独特的挑战。这些团队成员只需要超出普通最终用户级别的访问权限的子集;但是,他们几乎总是告诉管理层,如果没有超级用户访问权限,他们就无法执行他们的任务。值得庆幸的是,没有理由向最终用户提供此类访问权限,因为存在工具可以管理这种确切的需求。
即使是管理员也应该在不需要时限制其权限。 |
到目前为止,安全章节已经介绍了允许授权用户访问并试图阻止未经授权的访问。一旦授权用户获得了对系统资源的访问权限,就会出现另一个问题。在许多情况下,某些用户可能需要访问应用程序启动脚本,或者一组管理员需要维护系统。传统上,标准用户和组、文件权限,甚至 su(1) 命令将管理此访问权限。随着应用程序需要更多访问权限,随着更多用户需要使用系统资源,需要一个更好的解决方案。目前最常用的应用程序是 Sudo。
Sudo 允许管理员为系统命令配置更严格的访问权限,并提供一些高级日志记录功能。作为一种工具,它可以从 Ports Collection 中获得,作为 security/sudo 或通过使用 pkg(8) 实用程序获得。
执行以下命令来安装它
# pkg install sudo
安装完成后,安装的 visudo
将使用文本编辑器打开配置文件。强烈建议使用 visudo
,因为它内置语法检查器,可在保存文件之前验证是否存在错误。
配置文件由多个小节组成,允许进行广泛的配置。在以下示例中,Web 应用程序维护人员 user1 需要启动、停止和重启名为 webservice 的 Web 应用程序。要授予此用户执行这些任务的权限,请将以下行添加到 /usr/local/etc/sudoers 文件末尾
user1 ALL=(ALL) /usr/sbin/service webservice *
现在,用户可以使用以下命令启动 webservice
% sudo /usr/sbin/service webservice start
虽然此配置允许单个用户访问 webservice 服务;但是,在大多数组织中,有一个完整的 Web 团队负责管理该服务。一行代码也可以授予整个组的访问权限。以下步骤将创建一个 Web 组,将用户添加到该组,并允许该组的所有成员管理该服务
# pw groupadd -g 6001 -n webteam
使用相同的 pw(8) 命令,将用户添加到 webteam 组
# pw groupmod -m user1 -n webteam
最后,/usr/local/etc/sudoers 中的这行代码允许 webteam 组的任何成员管理 webservice
%webteam ALL=(ALL) /usr/sbin/service webservice *
大多数组织正在转向或已经转向双因素身份验证模型。在这种情况下,用户可能没有密码输入。 sudo(8) 可以配置为通过使用 %webteam ALL=(ALL) NOPASSWD: /usr/sbin/service webservice * |
16.3.5. 使用 Doas 共享管理
使用 doas,用户可以使用提升的权限(通常以 root 用户身份)执行命令,同时保持简化的安全方法。与 sudo(8) 不同,doas 强调简洁和极简主义,专注于简化的权限委托,而不是大量的配置选项。
执行以下命令来安装它
# pkg install doas
安装后,必须配置 /usr/local/etc/doas.conf 以授予用户对特定命令或角色的访问权限。
最简单的条目可能是以下内容,它授予用户 local_user
以 root
权限,在执行 doas 命令时无需输入密码。
permit nopass local_user as root
安装和配置 doas
实用程序后,现在可以使用增强权限执行命令,例如
$ doas vi /etc/rc.conf
有关更多配置示例,请阅读 doas.conf(5)。
16.4. 入侵检测系统 (IDS)
验证系统文件和二进制文件非常重要,因为它为系统管理员和安全团队提供有关系统更改的信息。监视系统更改的软件应用程序称为入侵检测系统 (IDS)。
FreeBSD 为称为 mtree(8) 的基本 IDS 系统提供本机支持。虽然夜间安全电子邮件会通知管理员更改,但信息存储在本地,并且恶意用户有可能修改此信息以隐藏他们对系统的更改。因此,建议创建一个单独的二进制签名集,并将它们存储在只读的、root 拥有的目录中,或者最好是存储在可移动的 USB 磁盘或远程服务器上。
还建议在每次更新后运行 freebsd-update IDS
。
16.4.1. 生成规范文件
内置的 mtree(8) 实用程序可用于生成目录内容的规范。种子(或数值常量)用于生成规范,并且需要检查规范是否已更改。这使得可以确定文件或二进制文件是否已被修改。由于攻击者不知道种子值,因此伪造或检查文件的校验和值将非常困难,甚至不可能。
建议为包含二进制文件和配置文件的目录以及包含敏感数据的任何目录创建规范。通常,会为 /bin、/sbin、/usr/bin、/usr/sbin、/usr/local/bin、/etc 和 /usr/local/etc 创建规范。 |
以下示例生成一组 sha512
哈希值(每个 /bin 中的系统二进制文件一个),并将这些值保存到用户主目录中的隐藏文件 /home/user/.bin_chksum_mtree
# mtree -s 123456789 -c -K cksum,sha512 -p /bin > /home/user/.bin_chksum_mtree
输出应类似于以下内容
mtree: /bin checksum: 3427012225
务必将种子值和校验和输出隐藏起来,以防恶意用户访问。 |
16.4.2. 规范文件结构
mtree 格式是一种文本格式,描述了文件系统对象的集合。此类文件通常用于创建或验证目录层次结构。
mtree 文件由一系列行组成,每行提供有关单个文件系统对象的的信息。始终忽略前导空格。
上面创建的规范文件将用于解释格式和内容
# user: root (1) # machine: machinename (2) # tree: /bin (3) # date: Thu Aug 24 21:58:37 2023 (4) # . /set type=file uid=0 gid=0 mode=0555 nlink=1 flags=uarch (5) . type=dir mode=0755 nlink=2 time=1681388848.239523000 (6) \133 nlink=2 size=12520 time=1685991378.688509000 \ cksum=520880818 \ sha512=5c1374ce0e2ba1b3bc5a41b23f4bbdc1ec89ae82fa01237f376a5eeef41822e68f1d8f75ec46b7bceb65396c122a9d837d692740fdebdcc376a05275adbd3471 cat size=14600 time=1685991378.694601000 cksum=3672531848 \ (7) sha512=b30b96d155fdc4795432b523989a6581d71cdf69ba5f0ccb45d9b9e354b55a665899b16aee21982fffe20c4680d11da4e3ed9611232a775c69f926e5385d53a2 chflags size=8920 time=1685991378.700385000 cksum=1629328991 \ sha512=289a088cbbcbeb436dd9c1f74521a89b66643976abda696b99b9cc1fbfe8b76107c5b54d4a6a9b65332386ada73fc1bbb10e43c4e3065fa2161e7be269eaf86a chio size=20720 time=1685991378.706095000 cksum=1948751604 \ sha512=46f58277ff16c3495ea51e74129c73617f31351e250315c2b878a88708c2b8a7bb060e2dc8ff92f606450dbc7dd2816da4853e465ec61ee411723e8bf52709ee chmod size=9616 time=1685991378.712546000 cksum=4244658911 \ sha512=1769313ce08cba84ecdc2b9c07ef86d2b70a4206420dd71343867be7ab59659956f6f5a458c64e2531a1c736277a8e419c633a31a8d3c7ccc43e99dd4d71d630
1 | 创建规范的用户。 |
2 | 机器的主机名。 |
3 | 目录路径。 |
4 | 创建规范的日期和时间。 |
5 | /set 特殊命令,定义从分析的文件中获得的一些设置。 |
6 | 引用解析的目录,并指示其类型、模式、硬链接数量以及自上次修改以来的 Unix 时间。 |
7 | 引用文件并显示大小、时间以及用于验证完整性的哈希值列表。 |
16.4.3. 验证规范文件
要验证二进制签名是否已更改,请将目录的当前内容与先前生成的规范进行比较,并将结果保存到文件中。
此命令需要用于生成原始规范的种子
# mtree -s 123456789 -p /bin < /home/user/.bin_chksum_mtree >> /home/user/.bin_chksum_output
这应该会生成与创建规范时生成的 /bin 相同的校验和。如果此目录中的二进制文件没有发生更改,则 /home/user/.bin_chksum_output 输出文件将为空。
为了模拟更改,请使用 touch(1) 更改 /bin/cat 的日期,然后再次运行验证命令
# touch /bin/cat
再次运行验证命令
# mtree -s 123456789 -p /bin < /home/user/.bin_chksum_mtree >> /home/user/.bin_chksum_output
然后检查输出文件的内容
# cat /root/.bin_chksum_output
输出应类似于以下内容
cat: modification time (Fri Aug 25 13:30:17 2023, Fri Aug 25 13:34:20 2023)
这只是一个示例,展示了执行命令时会显示的内容,以显示元数据中会发生的更改。 |
16.5. 安全级别
securelevel 是在内核中实现的安全机制。当安全级别为正时,内核会限制某些任务;即使是超级用户(root)也不允许执行这些任务。
securelevel 机制限制了以下功能
取消设置某些文件标志,例如
schg
(系统不可变标志)。通过 /dev/mem 和 /dev/kmem 写入内核内存。
加载内核模块。
更改防火墙规则。
16.5.1. 安全级别定义
内核以五个不同的安全级别运行。任何超级用户进程都可以提高级别,但没有任何进程可以降低级别。
安全定义如下
- -1
永久不安全模式 - 始终以不安全模式运行系统。这是默认的初始值。
- 0
不安全模式 - 不可变和追加只写标志可以关闭。所有设备都可以读取或写入,受其权限限制。
- 1
安全模式 - 系统不可变和系统追加只写标志不能关闭;已安装文件系统的磁盘、/dev/mem 和 /dev/kmem 不能打开以供写入;/dev/io(如果您的平台有此功能)根本无法打开;内核模块(参见 kld(4))不能加载或卸载。内核调试器不能使用 debug.kdb.enter sysctl 进入。不能使用 debug.kdb.panic、debug.kdb.panic_str 和其他 sysctl 强制发生恐慌或陷阱。
- 2
高度安全模式 - 与安全模式相同,此外磁盘不能打开以供写入(除了由 mount(2) 打开),无论是否已安装。此级别可以防止通过卸载来篡改文件系统,但也会抑制在系统处于多用户模式时运行 newfs(8)。
- 3
网络安全模式 - 与高度安全模式相同,另外,IP 数据包过滤规则(请参见 ipfw(8)、ipfirewall(4) 和 pfctl(8))无法更改,并且 dummynet(4) 或 pf(4) 配置无法调整。
总而言之,FreeBSD 安全级别中 |
16.6. 文件标志
文件标志允许用户除了基本权限和所有权之外,还将其他元数据或属性附加到文件和目录。这些标志提供了一种方法来控制文件的各种行为和属性,而无需创建特殊目录或使用扩展属性。
文件标志可用于实现不同的目标,例如防止文件删除、使文件只追加、同步文件更新等等。FreeBSD 中一些常用的文件标志包括“不可变”标志,它可以防止修改或删除文件,以及“只追加”标志,它只允许将数据添加到文件的末尾,但不能修改或删除。
这些标志可以使用 FreeBSD 中的 chflags(1) 命令来管理,从而为管理员和用户提供对文件和目录的行为和特征的更多控制。请注意,文件标志通常由 root 或具有适当权限的用户管理,因为它们会影响文件的访问和操作方式。一些标志可供文件所有者使用,如 chflags(1) 中所述。
16.6.1. 使用文件标志
在这个例子中,用户主目录中名为 ~/important.txt 的文件需要防止删除。
执行以下命令设置schg
文件标志
# chflags schg ~/important.txt
当任何用户(包括root
用户)尝试删除该文件时,系统将显示以下消息
rm: important.txt: Operation not permitted
要删除该文件,需要通过执行以下命令删除该文件的标志
# chflags noschg ~/important.txt
支持的文件标志及其功能列表可以在 chflags(1) 中找到。
16.7. OpenSSH
OpenSSH 是一组网络连接工具,用于提供对远程机器的安全访问。此外,TCP/IP 连接可以通过 SSH 连接安全地进行隧道传输或转发。OpenSSH 对所有流量进行加密,以消除窃听、连接劫持和其他网络级攻击。
OpenSSH 由 OpenBSD 项目维护,默认情况下在 FreeBSD 中安装。
当数据以未加密的形式通过网络发送时,客户端和服务器之间的任何网络嗅探器都可以窃取用户/密码信息或会话期间传输的数据。OpenSSH 提供了各种身份验证和加密方法来防止这种情况发生。
有关 OpenSSH 的更多信息,请访问 网页。
本节概述了内置客户端实用程序,用于安全地访问其他系统并从 FreeBSD 系统安全地传输文件。然后介绍了如何在 FreeBSD 系统上配置 SSH 服务器。
如前所述,本章将介绍 OpenSSH 的基础系统版本。 security/openssh-portable 中也提供了一个 OpenSSH 版本,它提供了额外的配置选项,并且更定期地更新新功能。 |
16.7.1. 使用 SSH 客户端实用程序
要登录 SSH 服务器,请使用 ssh(1) 并指定服务器上存在的用户名以及服务器的 IP 地址或主机名。如果这是第一次连接到指定的服务器,则会提示用户首先验证服务器的指纹
# ssh [email protected]
输出应类似于以下内容
The authenticity of host 'example.com (10.0.0.1)' can't be established. ECDSA key fingerprint is 25:cc:73:b5:b3:96:75:3d:56:19:49:d2:5c:1f:91:3b. Are you sure you want to continue connecting (yes/no)? yes Permanently added 'example.com' (ECDSA) to the list of known hosts. Password for [email protected]: user_password
SSH 利用指纹系统来验证客户端连接时服务器的真实性。当用户第一次连接时通过输入yes
来接受密钥的指纹时,密钥的副本将保存到用户主目录中的 ~/.ssh/known_hosts 中。将来尝试登录将根据保存的密钥进行验证,并且 ssh(1) 将在服务器密钥与保存的密钥不匹配时显示警报。如果发生这种情况,用户应该首先验证密钥更改的原因,然后再继续连接。
如何执行此检查超出了本章的范围。 |
使用 scp(1) 安全地将文件复制到远程机器或从远程机器复制文件。
此示例将远程系统上的COPYRIGHT
复制到本地系统当前目录中的同名文件
# scp [email protected]:/COPYRIGHT COPYRIGHT
输出应类似于以下内容
Password for [email protected]: ******* COPYRIGHT 100% |*****************************| 4735
由于该主机的指纹已经过验证,因此在提示用户输入密码之前,会自动检查服务器的密钥。
传递给 scp(1) 的参数类似于 cp(1)。要复制的文件或文件是第一个参数,要复制到的目标是第二个参数。由于文件是从网络上获取的,因此一个或多个文件参数采用user@host:<path_to_remote_file>
的形式。请注意,在递归地复制目录时,scp(1) 使用-r
,而 cp(1) 使用-R
。
要打开一个交互式会话来复制文件,请使用 sftp(1)。
16.7.2. 基于密钥的身份验证
客户端可以使用密钥来配置连接到远程机器,而不是使用密码。出于安全原因,这是首选方法。
ssh-keygen(1) 可用于生成身份验证密钥。要生成公钥和私钥对,请指定密钥类型并按照提示操作。建议使用一个难于猜测但易于记忆的密码来保护密钥。
% ssh-keygen -t rsa -b 4096
输出应类似于以下内容
Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Created directory '/home/user/.ssh/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_rsa. Your public key has been saved in /home/user/.ssh/id_rsa.pub. The key fingerprint is: SHA256:54Xm9Uvtv6H4NOo6yjP/YCfODryvUU7yWHzMqeXwhq8 [email protected] The key's randomart image is: +---[RSA 2048]----+ | | | | | | | . o.. | | .S*+*o | | . O=Oo . . | | = Oo= oo..| | .oB.* +.oo.| | =OE**.o..=| +----[SHA256]-----+
私钥存储在 ~/.ssh/id_rsa 中,公钥存储在 ~/.ssh/id_rsa.pub 中。要使基于密钥的身份验证正常工作,公钥必须复制到远程机器上的 ~/.ssh/authorized_keys 中。
为 OpenSSH 密钥使用密码是一种重要的安全做法,它为防止未经授权的访问提供了一层额外的保护,并增强了整体网络安全。 如果丢失或被盗,这将增加另一层安全性。 |
16.7.3. SSH 隧道
OpenSSH 能够创建隧道来封装另一个协议在加密会话中。
以下命令告诉 ssh(1) 创建一个隧道
% ssh -D 8080 [email protected]
此示例使用以下选项
- -D
指定一个本地“动态”应用程序级端口转发。
- [email protected]
要在指定的远程 SSH 服务器上使用的登录名。
SSH 隧道通过在指定的localport
上的localhost
上创建一个监听套接字来工作。
这种方法可用于封装任何数量的不安全 TCP 协议,例如 SMTP、POP3 和 FTP。
16.7.4. 启用 SSH 服务器
除了提供内置 SSH 客户端实用程序外,FreeBSD 系统还可以配置为 SSH 服务器,接受来自其他 SSH 客户端的连接。
如前所述,本章将介绍 OpenSSH 的基础系统版本。请不要与 security/openssh-portable 混淆,它是随 FreeBSD 端口一起提供的 OpenSSH 版本。 |
为了使 SSH 服务器在重启后保持启用状态,请执行以下命令
# sysrc sshd_enable="YES"
然后执行以下命令启用服务
# service sshd start
sshd 第一次在 FreeBSD 系统上启动时,系统的主机密钥将自动创建,并且指纹将显示在控制台上。请向用户提供指纹,以便他们第一次连接到服务器时能够验证指纹。
请参考 sshd(8) 以了解启动 sshd 时可用的选项列表以及有关身份验证、登录过程和各种配置文件的完整讨论。
此时,sshd 应该对系统中具有用户名和密码的所有用户可用。
16.7.5. 配置公钥认证方法
配置 OpenSSH 以使用公钥身份验证可以增强安全性,因为利用非对称加密技术进行身份验证。这种方法消除了与密码相关的风险,例如弱密码或传输过程中的拦截,同时阻止了各种基于密码的攻击。但是,必须确保私钥受到良好保护,以防止未经授权的访问。
第一步是配置 sshd(8) 以使用所需的身份验证方法。
编辑 /etc/ssh/sshd_config 并取消以下配置的注释
PubkeyAuthentication yes
配置完成后,用户将不得不向系统管理员发送他们的公钥,这些密钥将被添加到 .ssh/authorized_keys 中。生成密钥的过程在 基于密钥的身份验证 中有介绍。
然后重新启动服务器,执行以下命令
# service sshd reload
强烈建议您遵循 SSH 服务器安全选项 中指示的安全改进。
16.7.6. SSH 服务器安全选项
虽然 sshd 是 FreeBSD 最广泛使用的远程管理工具,但暴力攻击和随机攻击是任何暴露在公共网络上的系统都会遇到的常见问题。
本节将介绍一些可用于防止此类攻击成功的附加参数。所有配置都将在 /etc/ssh/sshd_config 中完成
请不要将 /etc/ssh/sshd_config 与 /etc/ssh/ssh_config 混淆(注意第一个文件名中的额外 |
默认情况下,可以使用公钥和密码进行身份验证。要仅允许公钥身份验证(强烈建议这样做),请更改变量
PasswordAuthentication no
限制哪些用户可以登录 SSH 服务器以及登录的来源是一个好主意,可以在 OpenSSH 服务器配置文件中使用 AllowUsers
关键字。例如,要仅允许 user
从 192.168.1.32
登录,请将以下行添加到 /etc/ssh/sshd_config 中
AllowUsers [email protected]
要允许 user
从任何地方登录,请列出该用户而不指定 IP 地址
AllowUsers user
多个用户应该在同一行上列出,如下所示
AllowUsers [email protected] user
在进行所有更改后,并在重新启动服务之前,建议通过执行以下命令验证所做的配置是否正确
# sshd -t
如果配置文件正确,则不会显示任何输出。如果配置文件不正确,它将显示类似以下内容
/etc/ssh/sshd_config: line 3: Bad configuration option: sdadasdasdasads /etc/ssh/sshd_config: terminating, 1 bad configuration options
在进行更改并检查配置文件是否正确后,通过运行以下命令告诉 sshd 重新加载其配置文件
# service sshd reload
16.8. OpenSSL
OpenSSL 是一个密码工具包,实现了安全套接字层 (SSL) 和传输层安全 (TLS) 网络协议以及许多密码例程。
openssl 程序是一个命令行工具,用于从 shell 使用 OpenSSL 密码库的各种密码功能。它可以用于
创建和管理私钥、公钥和参数
公钥密码操作
创建 X.509 证书、CSR 和 CRL
计算消息摘要
使用密码进行加密和解密
SSL/TLS 客户端和服务器测试
处理 S/MIME 签名或加密邮件
时间戳请求、生成和验证
对密码例程进行基准测试
有关 OpenSSL 的更多信息,请阅读免费的 OpenSSL Cookbook。
16.8.1. 生成证书
OpenSSL 支持生成证书,这些证书既可以由 CA 验证,也可以用于自身。
运行命令 openssl(1) 为 CA 生成有效的证书,并使用以下参数。此命令将在当前目录中创建两个文件。证书请求 req.pem 可以发送到 CA,它将验证输入的凭据,签署请求并返回签名证书。第二个文件 cert.key 是证书的私钥,应将其存储在安全位置。如果它落入他人手中,则可以使用它来冒充用户或服务器。
执行以下命令以生成证书
# openssl req -new -nodes -out req.pem -keyout cert.key -sha3-512 -newkey rsa:4096
输出应类似于以下内容
Generating a RSA private key ..................................................................................................................................+++++ ......................................+++++ writing new private key to 'cert.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ES State or Province Name (full name) [Some-State]:Valencian Community Locality Name (eg, city) []:Valencia Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []:Systems Administrator Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org Email Address []:[email protected] Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:123456789 An optional company name []:Another name
或者,如果不需要来自 CA 的签名,则可以创建自签名证书。这将在当前目录中创建两个新文件:一个私钥文件 cert.key 和证书本身 cert.crt。这些应该放在一个目录中,最好放在 /etc/ssl/ 下,该目录只能由 root
读取。0700
的权限适合这些文件,可以使用 chmod
设置。
执行以下命令以生成证书
# openssl req -new -x509 -days 365 -sha3-512 -keyout /etc/ssl/private/cert.key -out /etc/ssl/certs/cert.crt
输出应类似于以下内容
Generating a RSA private key ........................................+++++ ...........+++++ writing new private key to '/etc/ssl/private/cert.key' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:ES State or Province Name (full name) [Some-State]:Valencian Community Locality Name (eg, city) []:Valencia Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []:Systems Administrator Common Name (e.g. server FQDN or YOUR name) []:localhost.example.org Email Address []:[email protected]
16.8.2. 配置 FIPS 提供程序
随着 OpenSSL 3 导入到基本系统中(在 FreeBSD 14 及更高版本中),其新的提供程序模块概念在系统中被引入。除了库中内置的默认提供程序模块之外,legacy 模块实现了现在可选的已弃用的密码算法,而 fips 模块将 OpenSSL 实现限制为 FIPS 标准集中存在的密码算法。OpenSSL 的这部分接受了 特别关注,包括 相关安全问题的列表,并且定期接受 FIPS 140 验证流程。 FIPS 验证版本的列表 也可用。这允许用户确保他们在使用 OpenSSL 时符合 FIPS 标准。
重要的是,fips_module(7) 受额外的安全措施保护,防止在未通过完整性检查的情况下使用它。此检查可以由本地系统管理员设置,允许每个 OpenSSL 3 用户加载此模块。如果配置不正确,预计 FIPS 模块将按如下方式失败
# echo test | openssl aes-128-cbc -a -provider fips -pbkdf2
输出应类似于以下内容
aes-128-cbc: unable to load provider fips Hint: use -provider-path option or OPENSSL_MODULES environment variable. 00206124D94D0000:error:1C8000D5:Provider routines:SELF_TEST_post:missing config data:crypto/openssl/providers/fips/self_test.c:275: 00206124D94D0000:error:1C8000E0:Provider routines:ossl_set_error_state:fips module entering error state:crypto/openssl/providers/fips/self_test.c:373: 00206124D94D0000:error:1C8000D8:Provider routines:OSSL_provider_init_int:self test post failure:crypto/openssl/providers/fips/fipsprov.c:707: 00206124D94D0000:error:078C0105:common libcrypto routines:provider_init:init fail:crypto/openssl/crypto/provider_core.c:932:name=fips
可以通过在 /etc/ssl/fipsmodule.cnf 中创建文件来配置检查,该文件随后将在 OpenSSL 的主配置文件 /etc/ssl/openssl.cnf 中引用。OpenSSL 提供了 openssl-fipsinstall(1) 实用程序来帮助完成此过程,可以使用以下方式
# openssl fipsinstall -module /usr/lib/ossl-modules/fips.so -out /etc/ssl/fipsmodule.cnf
输出应类似于以下内容
INSTALL PASSED
然后应该修改 /etc/ssl/openssl.cnf,以便
包含上面生成的 /etc/ssl/fipsmodule.cnf 文件,
公开 FIPS 模块以供可能使用,
并显式激活默认模块。
[...] # For FIPS # Optionally include a file that is generated by the OpenSSL fipsinstall # application. This file contains configuration data required by the OpenSSL # fips provider. It contains a named section e.g. [fips_sect] which is # referenced from the [provider_sect] below. # Refer to the OpenSSL security policy for more information. .include /etc/ssl/fipsmodule.cnf [...] # List of providers to load [provider_sect] default = default_sect # The fips section name should match the section name inside the # included fipsmodule.cnf. fips = fips_sect # If no providers are activated explicitly, the default one is activated implicitly. # See man 7 OSSL_PROVIDER-default for more details. # # If you add a section explicitly activating any other provider(s), you most # probably need to explicitly activate the default provider, otherwise it # becomes unavailable in openssl. As a consequence applications depending on # OpenSSL may not work correctly which could lead to significant system # problems including inability to remotely access the system. [default_sect] activate = 1
完成此操作后,应该能够确认 FIPS 模块是否有效可用并正常工作
# echo test | openssl aes-128-cbc -a -provider fips -pbkdf2
输出应类似于以下内容
enter AES-128-CBC encryption password: Verifying - enter AES-128-CBC encryption password: U2FsdGVkX18idooW6e3LqWeeiKP76kufcOUClh57j8U=
每次修改 FIPS 模块时都需要重复此过程,例如,在执行系统更新后或在应用影响基本系统中 OpenSSL 的安全修复程序后。
16.9. Kerberos
Kerberos 是一种网络身份验证协议,最初由麻省理工学院 (MIT) 创建,作为一种在潜在敌对网络中安全提供身份验证的方法。Kerberos 协议使用强大的密码学,以便客户端和服务器都可以在不通过网络发送任何未加密的秘密的情况下证明其身份。Kerberos 可以被描述为一种身份验证代理系统,以及一种可信第三方身份验证系统。用户在通过 Kerberos 进行身份验证后,其通信可以被加密以确保隐私和数据完整性。
Kerberos 的唯一功能是在网络上提供用户的安全身份验证和服务器的身份验证。它不提供授权或审计功能。建议将 Kerberos 与其他提供授权和审计服务的安全方法一起使用。
当前版本的协议是版本 5,在 RFC 4120 中进行了描述。该协议有几个免费实现可用,涵盖了各种操作系统。MIT 继续开发其 Kerberos 软件包。它在美国通常用作密码产品,并且历来受到美国出口管制的约束。在 FreeBSD 中,MITKerberos 可作为 security/krb5 软件包或端口使用。Heimdal Kerberos 实现是在美国以外明确开发的,以避免出口管制。Heimdal Kerberos 发行版包含在 FreeBSD 基本安装中,另一个具有更多可配置选项的发行版作为 security/heimdal 在 Ports Collection 中可用。
在 Kerberos 中,用户和服务被识别为“主体”,它们包含在一个称为“领域”的管理分组中。典型的用户主体形式为 user@REALM
(领域通常为大写)。
本节提供有关如何使用 FreeBSD 中包含的 Heimdal 发行版设置 Kerberos 的指南。
为了演示 Kerberos 安装,命名空间将如下所示
DNS 域(区域)将为
example.org
。Kerberos 领域将为
EXAMPLE.ORG
。
在设置 Kerberos 时使用真实的域名,即使它将在内部运行。这避免了 DNS 问题并确保了与其他 Kerberos 领域的互操作性。 |
16.9.1. 设置 Heimdal KDC
密钥分发中心 (KDC) 是 Kerberos 提供的集中式身份验证服务,是系统中“可信第三方”。它是发出 Kerberos 票证的计算机,这些票证用于客户端向服务器进行身份验证。由于 KDC 被 Kerberos 领域中的所有其他计算机视为可信的,因此它具有更高的安全问题。应限制对 KDC 的直接访问。
虽然运行 KDC 需要很少的计算资源,但出于安全原因,建议使用专门的机器作为 KDC。
首先,安装 security/heimdal 软件包,如下所示
# pkg install heimdal
接下来,使用 sysrc
更新 /etc/rc.conf,如下所示
# sysrc kdc_enable=yes
# sysrc kadmind_enable=yes
接下来,编辑 /etc/krb5.conf,如下所示
[libdefaults] default_realm = EXAMPLE.ORG [realms] EXAMPLE.ORG = { kdc = kerberos.example.org admin_server = kerberos.example.org } [domain_realm] .example.org = EXAMPLE.ORG
在本例中,KDC 将使用完全限定的域名 kerberos.example.org
。KDC 的域名必须在 DNS 中可解析。
Kerberos 也可以使用 DNS 来定位 KDC,而不是 /etc/krb5.conf 中的 [realms]
部分。对于拥有自己的 DNS 服务器的大型组织,以上示例可以缩减为
[libdefaults] default_realm = EXAMPLE.ORG [domain_realm] .example.org = EXAMPLE.ORG
将以下行包含在 example.org
区域文件中
_kerberos._udp IN SRV 01 00 88 kerberos.example.org. _kerberos._tcp IN SRV 01 00 88 kerberos.example.org. _kpasswd._udp IN SRV 01 00 464 kerberos.example.org. _kerberos-adm._tcp IN SRV 01 00 749 kerberos.example.org. _kerberos IN TXT EXAMPLE.ORG
为了使客户端能够找到 Kerberos 服务,它们必须具有完全配置的 /etc/krb5.conf 或最少配置的 /etc/krb5.conf以及正确配置的 DNS 服务器。 |
接下来,创建 Kerberos 数据库,其中包含使用主密码加密的所有主体(用户和主机)的密钥。不需要记住此密码,因为它将存储在 /var/heimdal/m-key 中;为其使用 45 个字符的随机密码是合理的。要创建主密钥,请运行 kstash
并输入密码
# kstash
输出应类似于以下内容
Master key: xxxxxxxxxxxxxxxxxxxxxxx Verifying password - Master key: xxxxxxxxxxxxxxxxxxxxxxx
创建主密钥后,应初始化数据库。Kerberos 管理工具 kadmin(8) 可以以直接操作数据库的模式在 KDC 上使用,而无需使用 kadmind(8) 网络服务,如 kadmin -l
。这解决了在创建数据库之前尝试连接到它的“先有鸡还是先有蛋”问题。在 kadmin
提示符下,使用 init
创建领域的初始数据库
# kadmin -l
kadmin> init EXAMPLE.ORG
Realm max ticket life [unlimited]:
最后,在仍然处于 kadmin
中时,使用 add
创建第一个主体。现在坚持使用主体的默认选项,因为这些选项以后可以使用 modify
更改。在提示符下键入 ?
以查看可用选项。
kadmin> add tillman
输出应类似于以下内容
Max ticket life [unlimited]: Max renewable life [unlimited]: Principal expiration time [never]: Password expiration time [never]: Attributes []: Password: xxxxxxxx Verifying password - Password: xxxxxxxx
接下来,通过运行以下命令启动 KDC 服务
# service kdc start
# service kadmind start
虽然此时不会有任何 kerberized 守护进程运行,但可以通过获取刚创建的主题的票证来确认 KDC 是否正常运行
% kinit tillman
输出应类似于以下内容
[email protected]'s Password:
使用 klist
确认成功获得了票证
% klist
输出应类似于以下内容
Credentials cache: FILE:/tmp/krb5cc_1001 Principal: [email protected] Issued Expires Principal Aug 27 15:37:58 2013 Aug 28 01:37:58 2013 krbtgt/[email protected]
测试完成后,可以销毁临时票据。
% kdestroy
16.9.2. 配置服务器使用 Kerberos
配置服务器使用 Kerberos 身份验证的第一步是确保它在 /etc/krb5.conf 中具有正确的配置。可以使用 KDC 中的版本,也可以在新的系统上重新生成它。
接下来,在服务器上创建 /etc/krb5.keytab。这是“Kerberize”服务的关键部分 - 它对应于生成服务和 KDC 之间的共享密钥。该密钥是一个加密密钥,存储在“keytab”中。keytab 包含服务器的主机密钥,允许它和 KDC 验证彼此的身份。它必须以安全的方式传输到服务器,因为如果密钥公开,则服务器的安全性可能会被破坏。通常,keytab 是使用 kadmin
在管理员的受信任机器上生成的,然后以安全的方式传输到服务器,例如使用 scp(1);如果符合所需的安全性策略,它也可以直接在服务器上创建。以安全方式将 keytab 传输到服务器非常重要:如果其他方知道密钥,则该方可以冒充任何用户访问服务器!在服务器上直接使用 kadmin
很方便,因为 KDC 数据库中主机主体的条目也是使用 kadmin
创建的。
当然,kadmin
是一种 Kerberized 服务;需要 Kerberos 票据来验证网络服务的身份,但为了确保运行 kadmin
的用户实际存在(并且他们的会话没有被劫持),kadmin
会提示输入密码以获取新的票据。验证 kadmin 服务的身份的主体必须被允许使用 kadmin
接口,如 /var/heimdal/kadmind.acl 中所指定。有关设计访问控制列表的详细信息,请参见 info heimdal
中的“远程管理”部分。管理员可以安全地通过本地控制台或 ssh(1) 连接到 KDC,而不是启用远程 kadmin
访问,并使用 kadmin -l
在本地执行管理。
安装 /etc/krb5.conf 后,在 kadmin
中使用 add --random-key
。这会将服务器的主机主体添加到数据库中,但不会将主机主体密钥的副本提取到 keytab 中。要生成 keytab,请使用 ext
将服务器的主机主体密钥提取到其自己的 keytab 中
# kadmin
输出应类似于以下内容
kadmin> add --random-key host/myserver.example.org Max ticket life [unlimited]: Max renewable life [unlimited]: Principal expiration time [never]: Password expiration time [never]: Attributes []: kadmin> ext_keytab host/myserver.example.org kadmin> exit
请注意,ext_keytab
默认情况下将提取的密钥存储在 /etc/krb5.keytab 中。这在 Kerberized 服务器上运行时很好,但在其他地方提取 keytab 时,应该使用 --keytab path/to/file
参数
# kadmin
输出应类似于以下内容
kadmin> ext_keytab --keytab=/tmp/example.keytab host/myserver.example.org kadmin> exit
然后可以使用 scp(1) 或可移动介质将 keytab 安全地复制到服务器。请确保指定一个非默认的 keytab 名称,以避免将不必要的密钥插入系统的 keytab。
此时,服务器可以使用存储在 krb5.keytab 中的共享密钥从 KDC 读取加密消息。现在,它已准备好启用使用 Kerberos 的服务。最常见的一种这样的服务是 sshd(8),它通过 GSS-API 支持 Kerberos。在 /etc/ssh/sshd_config 中,添加以下行
GSSAPIAuthentication yes
进行此更改后,必须重新启动 sshd(8) 才能使新的配置生效:service sshd restart
。
16.9.3. 配置客户端使用 Kerberos
与服务器一样,客户端需要在 /etc/krb5.conf 中进行配置。根据需要将文件复制到适当的位置(安全地)或重新输入。
通过在客户端使用 kinit
、klist
和 kdestroy
来测试客户端,以获取、显示,然后删除现有主体的票据。Kerberos 应用程序还应该能够连接到启用了 Kerberos 的服务器。如果这不起作用,但获取票据可以,则问题可能出在服务器上,而不是客户端或 KDC 上。对于 Kerberized 的 ssh(1),GSS-API 默认情况下是禁用的,因此请使用 ssh -o GSSAPIAuthentication=yes hostname
进行测试。
在测试 Kerberized 应用程序时,请尝试使用数据包嗅探器(例如 tcpdump
)来确认没有敏感信息以明文形式发送。
有各种 Kerberos 客户端应用程序可用。随着桥梁的出现,使用 SASL 进行身份验证的应用程序也可以使用 GSS-API 机制,因此大量的客户端应用程序可以使用 Kerberos 进行身份验证,从 Jabber 客户端到 IMAP 客户端。
领域中的用户通常将其 Kerberos 主体映射到本地用户帐户。有时,需要授予没有匹配 Kerberos 主体的用户的本地用户帐户访问权限。例如,[email protected]
可能需要访问本地用户帐户 webdevelopers
。其他主体可能还需要访问该本地帐户。
位于用户主目录中的 .k5login 和 .k5users 文件可用于解决此问题。例如,如果将以下 .k5login 放置在 webdevelopers
的主目录中,则列出的两个主体都将拥有该帐户的访问权限,而无需共享密码
有关 .k5users 的更多信息,请参阅 ksu(1)。
16.9.4. MIT 的区别
MIT 和 Heimdal 实现之间的主要区别在于 kadmin
有一组不同的(但等效的)命令,并且使用不同的协议。如果 KDC 是 MIT,则 Heimdal 版本的 kadmin
无法用于远程管理 KDC,反之亦然。
客户端应用程序也可能使用略微不同的命令行选项来完成相同的任务。建议按照 http://web.mit.edu/Kerberos/www/ 上的说明进行操作。请注意路径问题:MIT 端口默认情况下安装到 /usr/local/ 中,如果 PATH
首先列出系统目录,则 FreeBSD 系统应用程序将运行,而不是 MIT 版本。
在 FreeBSD 上使用 MIT Kerberos 作为 KDC 时,执行以下命令将所需的配置添加到 /etc/rc.conf 中
# sysrc kdc_program="/usr/local/sbin/krb5kdc"
# sysrc kadmind_program="/usr/local/sbin/kadmind"
# sysrc kdc_flags=""
# sysrc kdc_enable="YES"
# sysrc kadmind_enable="YES"
16.9.5. Kerberos 提示、技巧和故障排除
在配置和排除 Kerberos 故障时,请牢记以下几点
从端口使用 Heimdal 或 MITKerberos 时,确保
PATH
在系统版本之前列出端口的客户端应用程序版本。如果领域中的所有计算机都没有同步的时间设置,则身份验证可能会失败。“使用 NTP 进行时钟同步” 描述了如何使用 NTP 同步时钟。
如果更改了主机名,则必须更改
host/
主体并更新 keytab。这也适用于特殊 keytab 条目,例如 Apache 的 www/mod_auth_kerb 使用的HTTP/
主体。领域中的所有主机都必须在 DNS 中可正向和反向解析,或者至少存在于 /etc/hosts 中。CNAME 可以使用,但 A 和 PTR 记录必须正确且已就位。无法解析主机的错误消息并不直观:
Kerberos5 refuses authentication because Read req failed: Key table entry not found
。一些充当 KDC 客户端的操作系统没有设置
ksu
的权限以使其设置为root
。这意味着ksu
不起作用。这是一个权限问题,而不是 KDC 错误。使用 MITKerberos 时,要允许主体拥有比默认的 10 小时票据生命周期更长的生命周期,请在 kadmin(8) 提示符处使用
modify_principal
来更改问题主体和krbtgt
主体的maxlife
。然后,主体可以使用kinit -l
请求具有更长生命周期的票据。在工作站上运行
kinit
时,在 KDC 上运行数据包嗅探器以帮助排除故障时,票据授予票据 (TGT) 会立即发送,甚至在输入密码之前。这是因为 Kerberos 服务器会向任何未经授权的请求自由传输 TGT。但是,每个 TGT 都是使用从用户密码派生的密钥加密的。当用户输入其密码时,它不会发送到 KDC,而是用于解密kinit
已经获得的 TGT。如果解密过程导致具有有效时间戳的有效票据,则用户具有有效的 Kerberos 凭据。这些凭据包括用于将来与 Kerberos 服务器建立安全通信的会话密钥,以及实际的 TGT,它使用 Kerberos 服务器自己的密钥加密。第二层加密允许 Kerberos 服务器验证每个 TGT 的真实性。主机主体可以具有更长的票据生命周期。如果用户主体的生命周期为一周,但连接到的主机的生命周期为 9 个小时,则用户缓存将具有已过期的主机主体,并且票据缓存将无法按预期工作。
在设置 krb5.dict 以防止使用特定错误密码(如 kadmind(8) 中所述)时,请记住它仅适用于已分配密码策略的主体。在 krb5.dict 中使用的格式是每行一个字符串。创建指向 /usr/share/dict/words 的符号链接可能很有用。
16.9.6. 减轻 Kerberos 限制
由于 Kerberos 是一种全有或全无的方法,因此网络上启用的所有服务都必须修改为与 Kerberos 一起工作,或者以其他方式保护免受网络攻击。这是为了防止用户凭据被盗并重复使用。例如,当在所有远程 shell 上启用 Kerberos 时,但非 Kerberized POP3 邮件服务器以明文形式发送密码。
KDC 是一个单点故障。根据设计,KDC 必须与其主密码数据库一样安全。KDC 绝对不应该运行任何其他服务,并且应该在物理上安全。危险性很高,因为 Kerberos 将所有密码用存储在 KDC 上的文件中的相同主密钥进行加密。
主密钥被泄露并没有像人们担心的那么糟糕。主密钥只用于加密 Kerberos 数据库,并用作随机数生成器的种子。只要 KDC 访问安全,攻击者就无法用主密钥做太多事情。
如果 KDC 无法使用,网络服务将无法使用,因为无法进行身份验证。这可以通过使用一个主 KDC 和一个或多个从属服务器,以及仔细实现使用 PAM 的辅助或回退身份验证来缓解。
Kerberos 允许用户、主机和服务相互之间进行身份验证。它没有机制来向用户、主机或服务验证 KDC。这意味着被篡改的 kinit
可以记录所有用户名和密码。像 security/tripwire 这样的文件系统完整性检查工具可以缓解这种情况。
16.10. TCP Wrappers
TCP Wrappers 是一种基于主机的网络访问控制系统。通过在传入网络请求到达实际网络服务之前拦截它们,TCP Wrappers 根据配置文件中预定义的规则评估源 IP 地址是否允许或拒绝访问。
但是,虽然 TCP Wrappers 提供基本访问控制,但不应将其视为更强大的安全措施的替代品。为了获得全面保护,建议使用防火墙等高级技术,以及适当的用户身份验证实践和入侵检测系统。
16.10.1. 初始配置
# sysrc inetd_enable="YES"
# service inetd start
然后,正确配置 /etc/hosts.allow。
与 TCP Wrappers 的其他实现不同,在 FreeBSD 中不建议使用 hosts.deny。所有配置选项都应放在 /etc/hosts.allow 中。 |
在最简单的配置中,守护进程连接策略设置为允许或阻止,具体取决于 /etc/hosts.allow 中的选项。FreeBSD 中的默认配置是允许所有连接到使用 inetd 启动的守护进程。
基本配置通常采用 daemon : address : action
的形式,其中 daemon
是 inetd 启动的守护进程,address
是有效的 hostname、IP 地址或括号 ([ ]) 中的 IPv6 地址,而 action
则是 allow
或 deny
。TCP Wrappers 使用首个匹配规则的语义,这意味着从头开始扫描配置文件以查找匹配的规则。当找到匹配项时,将应用该规则,并且搜索过程停止。
例如,要允许通过 mail/qpopper 守护进程进行 POP3 连接,应将以下行追加到 /etc/hosts.allow
# This line is required for POP3 connections: qpopper : ALL : allow
每当编辑此文件时,请重新启动 inetd
# service inetd restart
16.10.2. 高级配置
TCP Wrappers 提供高级选项,允许更精细地控制连接的处理方式。在某些情况下,可能需要向某些主机或守护进程连接返回注释。在其他情况下,应记录日志条目或向管理员发送电子邮件。其他情况可能需要使用仅用于本地连接的服务。这可以通过使用称为通配符、扩展字符和外部命令执行的配置选项来实现。要了解有关通配符及其相关功能的更多信息,请参考 hosts_access(5)。
16.11. 访问控制列表
访问控制列表 (ACL) 通过允许对每个文件或每个目录的用户和组进行细粒度的访问控制,扩展了传统的 UNIX® 文件权限。每个 ACL 条目定义一个用户或组以及关联的权限,例如读、写和执行。FreeBSD 提供了诸如 getfacl(1) 和 setfacl(1) 之类的命令来管理 ACL。
ACL 在需要比标准权限更具体的访问控制的场景中很有用,通常用于多用户环境或共享主机。但是,复杂性可能是不可避免的,但需要仔细规划才能确保提供所需的安全性。
FreeBSD 支持在 UFS 和 OpenZFS 中实现 NFSv4 ACL。请注意,setfacl(1) 命令的一些参数仅适用于 POSIX ACL,而另一些则适用于 NFSv4 ACL。 |
16.11.1. 在 UFS 中启用 ACL 支持
ACL 由挂载时管理标志 acls
启用,该标志可以添加到 /etc/fstab 中。
因此,将需要访问 /etc/fstab,并在选项部分添加 acls
标志,如下所示
# Device Mountpoint FStype Options Dump Pass# /dev/ada0s1a / ufs rw,acls 1 1
16.11.2. 获取 ACL 信息
可以使用 getfacl(1) 检查文件或目录的 ACL。
例如,要查看 ~/test 文件的 ACL 设置,请执行以下命令
% getfacl test
如果使用 NFSv4 ACL,输出应类似于以下内容
# file: test # owner: freebsduser # group: freebsduser owner@:rw-p--aARWcCos:-------:allow group@:r-----a-R-c--s:-------:allow everyone@:r-----a-R-c--s:-------:allow
如果使用 POSIX.1e ACL,输出应类似于以下内容
# file: test # owner: freebsduser # group: freebsduser user::rw- group::r-- other::r--
16.11.3. 使用 ACL
setfacl(1) 可用于向文件或目录添加、修改或删除 ACL。
如上所述,setfacl(1) 的一些参数不适用于 NFSv4 ACL,反之亦然。本节介绍如何针对 POSIX ACL 和 NFSv4 ACL 执行命令,并展示了这两个示例。
例如,要设置 POSIX.1e 默认 ACL 的强制元素
% setfacl -d -m u::rwx,g::rx,o::rx,mask::rwx directory
此示例为文件所有者的 POSIX.1e ACL 条目设置读、写和执行权限,并为文件上的邮件组设置读和写权限
% setfacl -m u::rwx,g:mail:rw file
要与上一个示例中相同,但在 NFSv4 ACL 中执行
% setfacl -m owner@:rwxp::allow,g:mail:rwp::allow file
要从 POSIX.1e ACL 中的文件中删除所有 ACL 条目,除了三个必需的条目
% setfacl -bn file
要删除 NFSv4 ACL 中的所有 ACL 条目
% setfacl -b file
有关这些命令的可用选项的更多信息,请参考 getfacl(1) 和 setfacl(1)。
16.12. Capsicum
Capsicum 是一种轻量级操作系统功能和沙箱框架,它实现了混合功能系统模型。功能是不可伪造的授权令牌,可以委派,必须出示才能执行操作。Capsicum 将文件描述符变成功能。
Capsicum 可用于应用程序和库的隔离,将更大的软件主体分解成隔离的(沙箱)组件,以实施安全策略并限制软件漏洞的影响。
16.13. 进程会计
进程会计是一种安全方法,管理员可以使用该方法跟踪所用系统资源及其在用户之间的分配,提供系统监控,以及以最小的程度跟踪用户的命令。
进程会计有正面和负面。一个好处是,入侵可以缩小到入口点。一个缺点是进程会计生成的日志数量,以及它们可能需要的磁盘空间。本节将指导管理员了解进程会计的基础知识。
如果需要更细粒度的会计,请参考 安全事件审计。 |
16.13.1. 启用和使用进程会计
在使用进程会计之前,必须使用以下命令启用它
# sysrc accounting_enable=yes
# service accounting start
会计信息存储在位于 /var/account 的文件中,该文件将在需要时自动创建,这是会计服务第一次启动时。这些文件包含敏感信息,包括所有用户发出的所有命令。对这些文件的写入权限仅限于 root
,而读取权限仅限于 root
和 wheel
组的成员。要阻止 wheel
成员读取这些文件,请将 /var/account 目录的模式更改为仅允许 root
访问。
启用后,会计将开始跟踪信息,例如 CPU 统计信息和已执行的命令。所有会计日志都采用非人类可读的格式,可以使用 sa(8) 查看。如果不带任何选项发出,sa(8) 将打印有关每个用户调用次数、总经过时间(分钟)、总 CPU 和用户时间(分钟)以及平均 I/O 操作次数的信息。有关控制输出的可用选项列表,请参考 sa(8)。
要显示用户发出的命令,请使用 lastcomm
。
例如,此命令打印出 trhodes
在 ttyp1
终端上所有使用 ls
的情况
# lastcomm ls trhodes ttyp1
还有许多其他有用的选项,这些选项在 lastcomm(1)、acct(5) 和 sa(8) 中进行了说明。
16.14. 资源限制
在 FreeBSD 中,资源限制是指控制和管理向进程和用户分配各种系统资源的机制。这些限制旨在防止单个进程或用户消耗过多的资源,这会导致性能下降或系统不稳定。资源限制有助于确保系统上所有活动进程和用户之间公平分配资源。
FreeBSD 提供了几种方法供管理员限制个人可以使用多少系统资源。
传统方法通过编辑 /etc/login.conf 来定义登录类。虽然此方法仍然受支持,但任何更改都需要一个多步骤过程,包括编辑此文件、重建资源数据库、对 /etc/master.passwd 进行必要的更改,以及重建密码数据库。这可能会很耗时,具体取决于要配置的用户数量。
rctl(8) 可用于提供更细粒度的方法来控制资源限制。此命令支持更多内容,因为它也可以用于对进程和 jail 设置资源约束。
本节将演示这两种控制资源的方法,从传统方法开始。
16.14.1. 资源类型
FreeBSD 为各种类型的资源提供了限制,包括
类型 | 描述 |
---|---|
CPU 时间 | 限制进程可以消耗的 CPU 时间 |
内存 | 控制进程可以使用的物理内存量 |
打开的文件 | 限制进程可以同时打开的文件数量 |
进程 | 控制用户或进程可以创建的进程数量 |
文件大小 | 限制进程可以创建的文件的最大大小 |
核心转储 | 控制进程是否允许生成核心转储文件 |
网络资源 | 限制进程可以使用的网络资源(例如,套接字)的数量。 |
有关类型的完整列表,请参阅 login.conf(5) 和 rctl(8)。
16.14.2. 配置登录类
在传统方法中,登录类和要应用于登录类的资源限制在 /etc/login.conf 中定义。每个用户帐户都可以分配到一个登录类,其中 default
是默认的登录类。每个登录类都有一组与之关联的登录功能。登录功能是 name=value
对,其中 name 是一个众所周知的标识符,value 是一个任意字符串,根据 name 不同进行相应的处理。
配置资源限制的第一步是通过执行以下命令打开 /etc/login.conf
# ee /etc/login.conf
然后找到要修改的用户类的部分。在本例中,假设用户类名为 limited
,如果不存在,则创建它。
limited:\ (1) :maxproc=50:\ (2) :tc=default: (3)
1 | 用户类的名称。 |
2 | 将 limited 类中用户的最大进程数 (maxproc) 设置为 50。 |
3 | 表示此用户类继承了 "default" 类中的默认设置。 |
修改 /etc/login.conf 文件后,运行 cap_mkdb(1) 生成 FreeBSD 用于应用这些设置的数据库。
# cap_mkdb /etc/login.conf
chpass(1) 可用于通过执行以下命令将类更改为所需的用户
# chpass username
这将打开一个文本编辑器,在其中添加新的 limited
类,如下所示
#Changing user information for username. Login: username Password: $6$2H.419USdGaiJeqK$6kgcTnDadasdasd3YnlNZsOni5AMymibkAfRCPirc7ZFjjv DVsKyXx26daabdfqSdasdsmL/ZMUpdHiO0 Uid [#]: 1001 Gid [# or name]: 1001 Change [month day year]: Expire [month day year]: Class: limited Home directory: /home/username Shell: /bin/sh Full Name: User & Office Location: Office Phone: Home Phone: Other information:
现在,分配给 limited
类的用户将具有 50 的最大进程限制。请记住,这只是使用 /etc/login.conf 文件设置资源限制的一个示例。
请记住,修改 /etc/login.conf 文件后,用户需要注销并重新登录才能使更改生效。此外,编辑系统配置文件时,尤其是在使用特权访问时,务必谨慎。
16.14.3. 启用和配置资源限制
rctl(8) 系统提供了一种更细粒度的设置和管理单个进程和用户的资源限制的方法。它允许您将资源限制动态分配给特定进程或用户,而不管其用户类如何。
使用 rctl(8) 的第一步是将以下行添加到 /boot/loader.conf 中并重新启动系统以启用它。
kern.racct.enable=1
然后通过执行以下命令启用并启动 rctl(8) 服务
# sysrc rctl_enable="YES"
# service rctl start
然后,rctl(8) 可用于设置系统规则。
规则语法 (rctl.conf(5)) 通过使用主体、主体 ID、资源和操作来控制,如以下示例规则所示
subject:subject-id:resource:action=amount/per
例如,要限制用户最多添加 10 个进程,请执行以下命令
# rctl -a user:username:maxproc:deny=10/user
要检查应用的资源限制,可以执行 rctl(8) 命令
# rctl
输出应类似于以下内容
user:username:maxproc:deny=10
如果规则已添加到 /etc/rctl.conf,则规则将保留在重新启动后。格式为规则,不带前面的命令。例如,前面的规则可以添加为
user:username:maxproc:deny=10
16.15. 监控第三方安全问题
近年来,安全领域在漏洞评估处理方面取得了很大进步。随着第三方实用程序的安装和配置,几乎适用于当今所有可用的操作系统,系统入侵的威胁也随之增加。
漏洞评估是安全性的关键因素。虽然 FreeBSD 发布了基本系统的公告,但为每个第三方实用程序发布公告超出了 FreeBSD 项目的能力。有一种方法可以减轻第三方漏洞并警告管理员已知安全问题。FreeBSD 附加实用程序称为 pkg,它包含专门用于此目的的选项。
pkg 会轮询数据库以查找安全问题。该数据库由 FreeBSD 安全团队和端口开发人员更新和维护。
安装提供 periodic(8) 配置文件,用于维护 pkg 审核数据库,并提供一种以编程方式保持其更新的方法。
安装后,以及随时审核作为 Ports Collection 部分的第三方实用程序,管理员可以选择更新数据库并通过调用以下命令查看已安装软件包的已知漏洞
% pkg audit -F
输出应类似于以下内容
vulnxml file up-to-date chromium-116.0.5845.96_1 is vulnerable: chromium -- multiple vulnerabilities CVE: CVE-2023-4431 CVE: CVE-2023-4427 CVE: CVE-2023-4428 CVE: CVE-2023-4429 CVE: CVE-2023-4430 WWW: https://vuxml.FreeBSD.org/freebsd/5fa332b9-4269-11ee-8290-a8a1599412c6.html samba413-4.13.17_5 is vulnerable: samba -- multiple vulnerabilities CVE: CVE-2023-3347 CVE: CVE-2023-34966 CVE: CVE-2023-34968 CVE: CVE-2022-2127 CVE: CVE-2023-34967 WWW: https://vuxml.FreeBSD.org/freebsd/441e1e1a-27a5-11ee-a156-080027f5fec9.html 2 problem(s) in 2 installed package(s) found.
通过将 Web 浏览器指向显示的 URL,管理员可以获取有关漏洞的更多信息。
这将包括受影响的版本,按 FreeBSD 端口版本划分,以及可能包含安全公告的其他网站。
16.16. FreeBSD 安全公告
与许多优质操作系统制造商一样,FreeBSD 项目也拥有一个安全团队,该团队负责确定每个 FreeBSD 版本的“生命周期结束”(EoL) 日期,并为尚未达到其 EoL 的受支持版本提供安全更新。有关 FreeBSD 安全团队和受支持版本的更多信息,请访问 FreeBSD 安全页面。
安全团队的一项任务是响应有关 FreeBSD 操作系统中报告的安全漏洞。确认漏洞后,安全团队会验证修复漏洞所需的步骤,并使用修复更新源代码。然后,它会将详细信息发布为“安全公告”。安全公告会发布在 FreeBSD 网站 上,并发送到 FreeBSD 安全通知邮件列表、FreeBSD 安全邮件列表 和 FreeBSD 公告邮件列表。
16.16.1. 安全公告的格式
以下是一个 FreeBSD 安全公告的示例
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 ============================================================================= FreeBSD-SA-23:07.bhyve Security Advisory The FreeBSD Project Topic: bhyve privileged guest escape via fwctl Category: core Module: bhyve Announced: 2023-08-01 Credits: Omri Ben Bassat and Vladimir Eli Tokarev from Microsoft Affects: FreeBSD 13.1 and 13.2 Corrected: 2023-08-01 19:48:53 UTC (stable/13, 13.2-STABLE) 2023-08-01 19:50:47 UTC (releng/13.2, 13.2-RELEASE-p2) 2023-08-01 19:48:26 UTC (releng/13.1, 13.1-RELEASE-p9) CVE Name: CVE-2023-3494 For general information regarding FreeBSD Security Advisories, including descriptions of the fields above, security branches, and the following sections, please visit <URL:https://security.FreeBSD.org/>. I. Background bhyve(8)'s fwctl interface provides a mechanism through which guest firmware can query the hypervisor for information about the virtual machine. The fwctl interface is available to guests when bhyve is run with the "-l bootrom" option, used for example when booting guests in UEFI mode. bhyve is currently only supported on the amd64 platform. II. Problem Description The fwctl driver implements a state machine which is executed when the guest accesses certain x86 I/O ports. The interface lets the guest copy a string into a buffer resident in the bhyve process' memory. A bug in the state machine implementation can result in a buffer overflowing when copying this string. III. Impact A malicious, privileged software running in a guest VM can exploit the buffer overflow to achieve code execution on the host in the bhyve userspace process, which typically runs as root. Note that bhyve runs in a Capsicum sandbox, so malicious code is constrained by the capabilities available to the bhyve process. IV. Workaround No workaround is available. bhyve guests that are executed without the "-l bootrom" option are unaffected. V. Solution Upgrade your vulnerable system to a supported FreeBSD stable or release / security branch (releng) dated after the correction date. Perform one of the following: 1) To update your vulnerable system via a binary patch: Systems running a RELEASE version of FreeBSD on the amd64, i386, or (on FreeBSD 13 and later) arm64 platforms can be updated via the freebsd-update(8) utility: # freebsd-update fetch # freebsd-update install Restart all affected virtual machines. 2) To update your vulnerable system via a source code patch: The following patches have been verified to apply to the applicable FreeBSD release branches. a) Download the relevant patch from the location below, and verify the detached PGP signature using your PGP utility. [FreeBSD 13.2] # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.2.patch # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.2.patch.asc # gpg --verify bhyve.13.2.patch.asc [FreeBSD 13.1] # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.1.patch # fetch https://security.FreeBSD.org/patches/SA-23:07/bhyve.13.1.patch.asc # gpg --verify bhyve.13.1.patch.asc b) Apply the patch. Execute the following commands as root: # cd /usr/src # patch < /path/to/patch c) Recompile the operating system using buildworld and installworld as described in <URL:https://freebsd.ac.cn/handbook/makeworld.html>. Restart all affected virtual machines. VI. Correction details This issue is corrected by the corresponding Git commit hash or Subversion revision number in the following stable and release branches: Branch/path Hash Revision - ------------------------------------------------------------------------- stable/13/ 9fe302d78109 stable/13-n255918 releng/13.2/ 2bae613e0da3 releng/13.2-n254625 releng/13.1/ 87702e38a4b4 releng/13.1-n250190 - ------------------------------------------------------------------------- Run the following command to see which files were modified by a particular commit: # git show --stat <commit hash> Or visit the following URL, replacing NNNNNN with the hash: <URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN> To determine the commit count in a working tree (for comparison against nNNNNNN in the table above), run: # git rev-list --count --first-parent HEAD VII. References <URL:https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-3494> The latest revision of this advisory is available at <URL:https://security.FreeBSD.org/advisories/FreeBSD-SA-23:07.bhyve.asc> -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmTJdsIACgkQbljekB8A Gu8Q1Q/7BFw5Aa0cFxBzbdz+O5NAImj58MvKS6xw61bXcYr12jchyT6ENC7yiR+K qCqbe5TssRbtZ1gg/94gSGEXccz5OcJGxW+qozhcdPUh2L2nzBPkMCrclrYJfTtM cnmQKjg/wFZLUVr71GEM95ZFaktlZdXyXx9Z8eBzow5rXexpl1TTHQQ2kZZ41K4K KFhup91dzGCIj02cqbl+1h5BrXJe3s/oNJt5JKIh/GBh5THQu9n6AywQYl18HtjV fMb1qRTAS9WbiEP5QV2eEuOG86ucuhytqnEN5MnXJ2rLSjfb9izs9HzLo3ggy7yb hN3tlbfIPjMEwYexieuoyP3rzKkLeYfLXqJU4zKCRnIbBIkMRy4mcFkfcYmI+MhF NPh2R9kccemppKXeDhKJurH0vsetr8ti+AwOZ3pgO21+9w+mjE+EfaedIi+JWhip hwqeFv03bAQHJdacNYGV47NsJ91CY4ZgWC3ZOzBZ2Y5SDtKFjyc0bf83WTfU9A/0 drC0z3xaJribah9e6k5d7lmZ7L6aHCbQ70+aayuAEZQLr/N1doB0smNi0IHdrtY0 JdIqmVX+d1ihVhJ05prC460AS/Kolqiaysun1igxR+ZnctE9Xdo1BlLEbYu2KjT4 LpWvSuhRMSQaYkJU72SodQc0FM5mqqNN42Vx+X4EutOfvQuRGlI= =MlAY -----END PGP SIGNATURE-----
每个安全公告都使用以下格式
每个安全公告都由安全主管的 PGP 密钥签名。可以在 OpenPGP 密钥 中验证安全主管的公钥。
安全公告的名称始终以
FreeBSD-SA-
(代表 FreeBSD 安全公告)开头,后跟两位数格式的年份 (23:
),后跟该年的公告编号 (07.
),后跟受影响的应用程序或子系统的名称 (bhyve
)。Topic
字段总结了漏洞。Category
指的是受影响的系统部分,可以是core
、contrib
或ports
之一。core
类别表示漏洞影响 FreeBSD 操作系统的核心组件。contrib
类别表示漏洞影响包含在 FreeBSD 中的软件,例如 BIND。ports
类别表示漏洞影响通过 Ports Collection 可用的软件。Module
字段指的是组件位置。在此示例中,bhyve
模块受影响;因此,此漏洞影响与操作系统一起安装的应用程序。Announced
字段反映了发布安全公告的日期。这意味着安全团队已确认问题存在,并且已将修补程序提交到 FreeBSD 源代码存储库。Credits
字段感谢发现漏洞并报告漏洞的个人或组织。Affects
字段说明哪些版本的 FreeBSD 受此漏洞影响。Corrected
字段指示已更正的日期、时间、时区偏移量和版本。括号中的部分显示了已合并修复的每个分支,以及来自该分支的对应版本的版本号。版本标识符本身包含版本号,以及适用的修补程序级别。修补程序级别是字母p
后跟一个数字,表示修补程序的序列号,允许用户跟踪已应用到系统的哪些修补程序。CVE Name
字段列出公共 cve.mitre.org 安全漏洞数据库中存在的公告编号(如果存在)。Background
字段提供受影响模块的说明。Problem Description
字段说明漏洞。这可能包括有关有缺陷代码的信息以及如何恶意使用实用程序的信息。Impact
字段描述问题对系统可能造成的影响类型。Workaround
字段指示如果无法立即修补系统,系统管理员是否可以使用变通方法。Solution
字段提供修补受影响系统的说明。这是一个经过测试和验证的分步方法,用于修补系统并使其安全运行。Correction Details
字段显示包含已更正代码的每个受影响的 Subversion 或 Git 分支及其修订号。References
字段提供有关漏洞的更多信息的来源。
最后修改时间:2024 年 9 月 23 日,作者 Fernando Apesteguía