> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20180506-an-quan/best-security-practices.md).

# 最佳安全实践

我们在谈论安全。每个人都喜欢安全。

黑客！盗窃！大屏幕上显示着坏家伙们把流量从一个国家路由到另一个国家的虚线！一队、二队、红队、蓝队！这让你心跳加速，甚至不用从椅子上站起来。

没人喜欢做那些阻止所有令人兴奋的黑客活动的事情。打补丁、锁定那些繁琐的小细节，感觉像在浪费时间。但实际上，最佳实践能节省时间。你打补丁花费的精力，相比从服务器中清理入侵者所需的精力微不足道。最佳系统管理实践，就像饮食和锻炼，会让人觉得枯燥乏味。而且，像饮食和锻炼一样，很少有人能就什么是最佳实践达成一致。

这里我提出我认为对每台主机都至关重要的安全实践。就 FreeBSD 而言，由于数十年的过时文档，弄清什么是最佳实践变得复杂。FreeBSD 12 废弃了 FreeBSD 6 中的许多最佳实践，而我们在 FreeBSD 1.1.2 中所做的事情已完全无关。

你的组织可能还有额外的实践要求。如果有集中式日志服务器、用于认证的 LDAP 服务器或 SSH 证书颁发机构，请使用它们。如果有 Ansible 等自动化系统，让它在你环境中实施这些实践。

始终从倾听 FreeBSD 开始。它会告诉你需要知道的大部分内容。

## 状态邮件

FreeBSD 使用 **periodic(8)** 命令每天、每周和每月调度自动系统检查。这些命令的结果会通过邮件发送给系统管理员。了解主机状况的最简单方法是定期阅读这些状态邮件。

邮件发送到本地主机的 root 账户。许多程序出问题时会发邮件给 root。最好进入 **/etc/aliases** 并将 root 的邮件重定向到一个有人实际阅读的地址，如下所示。

```sh
root: flunkies@mwl.io
```

保存文件并运行 **newaliases(8)**。

我认识的大多数系统管理员都有一个长期目标，就是减少收到的邮件量。是的，添加这些消息会阻碍这个目标。然而，这些邮件是协作开发的，只包含绝对最少的信息。你需要诸如“此软件包存在安全漏洞”和“你的 FreeBSD 版本刚刚过了生命周期终点，也许你应该趁还能升级时升级”之类的通知。

此外，你可以调整这些作业执行的检查。也许你有一个可靠的监控系统，总是能捕获分区或池即将填满的情况，你不希望邮件包含文件系统利用率信息。通过 **/etc/periodic.conf** 启用和禁用检查。与许多其他 FreeBSD 服务一样，你可以在 **/etc/defaults/periodic.conf** 中找到默认设置。通过在 `periodic.conf` 中将任务名称设为 `YES` 或 `NO`，你可以切换该检查。

浏览 **/etc/defaults/periodic.conf** 和 **/etc/periodic** 下的实际脚本。一些被禁用的作业在你的环境中可能有用。

如果你有大型员工团队，阅读服务器状态邮件是委派给初级系统管理员的绝佳任务。当我担任高级系统管理员时，通常会将主机设置为将所有 root 邮件发送到我邮件服务器上的别名。该别名将所有邮件重定向给我和我的“信任副手”——或者说，一个自认为值得信任并誓言会仔细阅读每封邮件、解决问题或将其引起我注意的副手。我可以抽查这些邮件，留意主机报告问题。当我的信任副手既不解决也不报告问题时，我会将她降级为“前信任副手”，真正的乐趣就开始了。

预定的 **periodic(8)** 作业不能涵盖你可能需要调度的所有内容。

## 更新检查

曾经，给 FreeBSD 应用安全补丁的唯一方法是从源代码构建操作系统。有经验的人可以只构建受影响的部分，避免构建整个树，但对于像 OpenSSL 这样深入各处的软件，这做法很可疑。但手动应用安全补丁最糟糕的不是构建，而是知道有补丁可用并确定底层问题是否影响你的主机。

**freebsd-update(8)** 程序为大多数 FreeBSD 用户极大地简化了安全补丁。安全补丁和升级只需要简单的命令。最重要的是，**freebsd-update(8)** 会告诉你是否有补丁可用。在 root 的 crontab 中添加一个检查安全更新的作业。

```sh
1 1 * * * freebsd-update cron
```

这告诉 **freebsd-update(8)** 等待随机分钟数，然后查询 FreeBSD 更新服务器是否有适用于你的 FreeBSD 版本的新安全补丁。如果发现新补丁，会下载并通过邮件通知 root。你的信任副手又有一次机会留意来自你主机的消息。

当你发现一组新的安全补丁时，去查看相应的安全公告。总会有的。看看这个问题对你影响有多严重。你是需要在午餐时打补丁，还是可以等到下班后或维护日？还是你需要因为 OpenSSL……再次重新签发所有 TLS 安全证书？

一旦你了解问题有多严重以及它对你的影响有多即时，就可以应用这些补丁。验证你有良好的备份。如果使用 ZFS，创建一个新的引导环境以便轻松回退。（虽然我从未遇到过 **freebsd-update(8)** 安全补丁出问题的情况，但我做系统管理员太久，不能不准备退路。）现在可以应用补丁了。

```sh
# freebsd-update install
```

你会被提示重启。根据打补丁的内容，freebsd-update 可能会告诉你重启并再次运行 `freebsd-update install`。遵循其指示。

**freebsd-update(8)** 检查还会通知你 FreeBSD 版本是否过了生命周期终止日期。这使得升级到更新版本至关重要。**freebsd-update(8)** 使更新到新版本变得容易，但它不会为你执行下载。它不知道你想升级到哪个版本。你是要运行 FreeBSD 11.5，还是跳到 12.1？这是一个只有你能做的决定。选择一个版本并用标志 `-r` 指定它。

```sh
# freebsd-update upgrade -r 12.1-RELEASE
```

烦人的是，版本名称必须与官方版本名称大小写一致。不是 12.1-release，而是 12.1-RELEASE。你将被提示比较主机上已更改的几个关键配置文件。决定是保留还是放弃更改。程序下载更新，然后你需要用另一个 `freebsd-update install` 命令安装它们。对于完整版本升级，你肯定需要重启并再次运行 `install` 命令。

如果你从源代码构建 FreeBSD 而不是使用 freebsd-update，那也没问题。我相信你有你的理由，它们可能——可能——甚至是合理的。只要确保你的环境能尽快在网络中分发升级。这通常通过在一个集中主机上构建，并让其他服务器 NFS 挂载 **/usr/src** 和 **/usr/obj** 以便快速安装来实现。

升级操作系统后，考虑你的软件包。

## 软件包

与其他开源操作系统相比，FreeBSD 的基本系统刻意保持小巧。它不附带现代图形环境、SQL 数据库甚至 Web 服务器。所有这些功能来自附加软件包。虽然这些软件包易于安装和维护，但它们需要与基本系统相同的专注和关爱。

FreeBSD 的软件包系统包含一个工具，用于检查已安装软件包中已知的安全漏洞——**pkg-audit(8)**。该工具作为每日状态检查的一部分每天运行，但这些运行只提供有已知安全漏洞的软件包名称。单独运行该工具会突出显示软件包问题。你可以让自动化系统在所有主机上运行 **pkg-audit(8)**，获取所有易受攻击软件包的主列表。

```sh
# pkg audit
python27-2.7.14_1 is vulnerable:
python 2.7 -- multiple vulnerabilities
CVE: CVE-2018-1061
CVE: CVE-2018-1060
CVE: CVE-2017-9233
CVE: CVE-2016-9063
CVE: CVE-2016-4472
CVE: CVE-2016-0718
CVE: CVE-2012-0876
WWW: https://vuxml.FreeBSD.org/freebsd/8719b935-8bae-41ad-92ba-3c826f651219.html
…
5 problem(s) in the installed packages found.
```

我们有几个软件包存在安全问题。CVE 标识符让你查找确切的缺陷及其影响。你可以用这些信息确定这些漏洞是否会影响你的环境。最简单的修复方法是查看 FreeBSD 是否有通过 `pkg upgrade` 升级的软件包。如果使用 ZFS，在升级软件包之前创建一个引导环境。这样可以轻松回退任何更改。

```sh
# pkg upgrade
Updating FreeBSD repository catalogue...
Fetching meta.txz: 100% 944 B 0.9kB/s 00:01
Fetching packagesite.txz: 100% 6 MiB 6.4MB/s 00:01
…
The following 2 package(s) will be affected (of 0 checked):

Installed packages to be UPGRADED:
perl5: 5.26.1 -> 5.26.2
freetype2: 2.8_1 -> 2.8_2

Number of packages to be upgraded: 2
14 MiB to be downloaded.

Proceed with this action? [y/N]: y
```

软件包管理器会下载并安装最新软件包。然后你可以再次运行 `pkg audit` 查看哪些软件包仍有问题。在本例中，python27 再次出现。软件包升级修复了已安装的 Perl 和 freetype2，但没有改变 python。看看 python27 中那些 CVE 编号，那是一长串问题。

一个程序怎么会有这么多问题？因为显然没人修复它们。

也许问题来自原始软件包。Python 2.7 可能有已知的安全问题，但 Python 作者可能认为消除这些问题会改变 Python 的行为，这是不可接受的。在某些软件中，软件作者可能质疑某个安全问题是否需要修复。无论如何，你知道问题存在总比不知道好。

也许软件供应商已创建了修复，但 FreeBSD 的 Port 尚未更新。也许 Port 已更新，但新软件包尚未构建并分发到镜像。也许修复后的软件包在尖端软件包中可用，但不在默认部署的季度分支中。

如果问题严重影响你，查看修复卡在哪里。开源软件由社区维护。这是你贡献的机会。如果你无法修复问题，至少可以确定修复何时可用。如果永远不会修复，你可以制定计划减轻风险。

## 包过滤

我强烈建议在所有主机上运行包过滤器。即使是简单的包过滤器，说“所有出站连接都允许，但只有这些入站连接”，也有助于防范恶意软件。不要依赖网络防火墙阻止所有恶意流量；如果有人混入网络，他们可能会从另一台机器攻击你的主机。虽然 FreeBSD 有三个不同的防火墙套件，但我的非正式调查显示，80% 的 FreeBSD 系统管理员更喜欢 **pf(4)**，所以我们用它。

从在 **/etc/pf.conf** 中创建简单的防火墙配置开始。

```sh
ext_if="em0"
set skip on lo
scrub in
block in
pass out
pass in on $ext_if proto tcp to ($ext_if) port {22, 53, 80, 443}
pass in on $ext_if proto udp to ($ext_if) port {53, 33433 >< 33626}
pass in on $ext_if proto icmp
```

此规则集禁止所有入站流量，但允许出站流量。然后我们允许四个 TCP 端口上的连接：22（SSH）、53（DNS）、80（HTTP）和 443（HTTPS）。我们还允许几个 UDP 端口：53 用于 DNS，33433 到 33626 用于 traceroute。最后，我们允许入站 ICMP。

如果你的主机不运行 DNS，请删除对端口 53 的 TCP 和 UDP 引用。如果没有 Web 服务器，可以删除 TCP 端口 80 和 443。你可能需要 traceroute 和 ping 用于诊断目的。

通过 **/etc/rc.conf** 中的 `pf_enable=YES` 条目启用 PF，然后用 `service pf start` 启动它。

我可以长篇大论地讨论非特权用户、安全级别和漏洞评估，但你可以在任何系统管理书籍中找到关于所有这些的丰富信息。如果你从这里开始配置你的 FreeBSD 系统，你会有一个良好的开端。

***

**MICHAEL W LUCAS** 著有多本 FreeBSD 书籍，包括《Absolute FreeBSD》和《FreeBSD Mastery》系列。更多信息见 <[www.michaelwlucas.com>。](https://freebsd-journal-cn.bsdcn.org/20180506-an-quan/http:/www.michaelwlucas.com>。)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20180506-an-quan/best-security-practices.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
