使用 Postfix 构建安全 SMTP 网关

作者:Mick Bauer

电子邮件是当今最流行和最重要的互联网服务,这使其成为网络罪犯和垃圾邮件制造者流行的目标。雪上加霜的是,配置 sendmail(最常用的邮件传输代理 (MTA))非常复杂、不直观且容易出错,这是一个不容回避的现实。

TCP 包装器和 SATAN 的杰出开发者 Wietse Venema 再次为我们带来了福音:他的程序 postfix 提供了一种替代 sendmail 的方案,它设计更简单、更模块化、更易于配置且更易于管理。同样重要的是,它的设计将可扩展性、可靠性和健全的安全性作为基本要求。

本文旨在快速向您介绍如何在网络上使用 postfix 作为安全手段,用于接收来自互联网主机的电子邮件并将其传递给互联网主机。特别是,我们将重点关注在防火墙、DMZ 和其他环境中部署 postfix,在这些环境中,它将暴露于与不受信任的系统接触。

sendmail 真的那么糟糕吗?这取决于您需要它做什么——如果您的电子邮件架构很简单,学习曲线可能不值得。但不可否认的是,sendmail 是一款极其强大、稳定且广泛部署的应用程序,它不会很快消失,也不应该消失。事实上,“偏执企鹅”可能会在未来几个月内推出一篇关于 sendmail 的文章。

背景:邮件传输代理

sendmail 和 postfix 都是邮件传输代理。MTA 将电子邮件从一个主机或网络移动到另一个主机或网络。这与邮件投递代理形成对比,后者在系统内移动邮件(即,从 MTA 到本地用户的邮箱,或从邮箱到文件或目录)。换句话说,MTA 就像在邮局之间运送邮件的邮车(以及飞机、火车等);邮件投递代理就像将邮件分发到目的地邮箱的邮递员。

除了 MTA 和 MDA 之外,还有各种类型的电子邮件阅读器,包括用于从远程系统检索电子邮件的 POP、POP3 和 IMAP 客户端。这些也称为邮件用户代理或 MUA。(对于这些没有真正的现实生活中的比喻,除非您的邮件每天都由一个仆人递给您,而他的唯一职责是时不时地检查您的邮箱!)但我们不关心这些或 MDA,除非提及它们与 MTA 的关系。

顺便说一句,如果您仍然使用 UUCP,postfix 也支持它(sendmail 也继续支持);大多数 MTA 支持各种交付“代理”,几乎总是至少支持 UUCP 和 SMTP。尽管如此,对于本文的其余部分,我们将假设您有兴趣将 postfix 用于 SMTP(简单邮件传输协议)传输。

SMTP 网关和 DMZ 网络

SMTP 的一个非常常见的用途,尤其是在内部使用 其他 电子邮件协议的组织中,是在互联网电子邮件网关上。由于 SMTP 是互联网电子邮件的 通用语言,因此任何需要在互联网上交换电子邮件的网络上都必须至少有一个 SMTP 主机。在这样的网络中,SMTP 网关充当内部非 SMTP 邮件服务器和外部 SMTP 主机之间的联络人。

这种“联络”功能本身不如以前那么重要了;当前版本的 Microsoft Exchange、Lotus Notes 和许多其他基于非 SMTP 的电子邮件服务器产品可以直接与 SMTP 服务器通信,没有问题。但是,仍然有理由让所有入站(甚至出站)电子邮件都到达单个点,主要原因是安全性。

使用 SMTP 网关有两个主要的安全性优势。首先,与保护多个内部电子邮件服务器相比,保护单个 SMTP 网关免受外部威胁要容易得多。其次,将互联网邮件与内部邮件分开,可以将互联网邮件事务完全移出内部网络。SMTP 网关的逻辑位置是在 DMZ(“非军事区”)网络中,该网络通过防火墙与互联网和内部网络隔离。

与 DNS、FTP、WWW 和任何其他公共访问服务一样,您可以在潜在的黑客目标和您的内部网络之间放置的保护越多越好。为您的防火墙添加额外的 NIC,将公共服务保存在单独的网络中,这是实现此目的最便宜且最有效的方法之一——只要您配置防火墙以仔细限制进出 DMZ 的流量)。这也是良好的风险管理;在(希望)不太可能发生的情况下,例如,您的 Web 服务器被攻破,它几乎不会成为攻击网络其余部分的便捷发射台。

(有关防火墙 DMZ 技术的更多信息,请参阅本期第 92 页的文章 </#147>保护 DNS 和 BIND</#148>。)

因此,即使只有一个电子邮件服务器的组织也应考虑添加 SMTP 网关,即使该电子邮件服务器已经具有 SMTP 功能。

但是,如果您的防火墙 您的 FTP 服务器、电子邮件服务器等怎么办?虽然对于任何服务托管使用防火墙都受到真正偏执狂的鄙视,但这对于非常小的网络(例如,具有宽带互联网连接的家庭用户)来说是很常见的做法。而且,在这个风雨飘摇的偏执狂看来,BIND 和 postfix 对防火墙的暴露远小于其他服务应用程序。

首先,DNS 和 SMTP 可能涉及不受信任的用户与服务器文件系统之间的较少直接接触。(我说“可能”,因为使用编写不良或配置马虎的软件,肯定有可能创建极其不安全的 DNS 和 SMTP 服务。)此外,BIND 和 postfix 都具有“chroot”选项并以非特权用户身份运行,这两个功能有助于降低任何一种服务被用来以某种方式获得 root 访问权限的危险(我们将在稍后深入讨论这两个选项。)

Postfix 架构:Postfix 如何工作?

要了解 postfix 的工作原理,考虑其背景非常有用。postfix 存在的主要目的是 sendmail 的复杂性。Postfix 是一个功能齐全的 MTA,因此它的核心功能与其他任何 MTA 相同。但是 postfix 的编写异常关注

  • 安全性。 Postfix 的设计将安全性作为基本要求,而不是事后才考虑。很明显,Venema 先生非常重视历史的教训(正如 CERT、bugtraq 等所记载的那样)。例如,系统不信任任何数据,无论其来源如何。并且在 chrooted jail(见下文)中使用最小权限,风险会降低。此外,还实施了针对缓冲区溢出和其他用户输入攻击的保护措施。如果某些东西仍然失败,postfix 的保护机制会尝试阻止其控制下的任何进程获得它们不应拥有的权利。由于 postfix 由许多彼此之间没有直接关系的不同程序组成,因此如果出现问题,此类问题被攻击者利用的可能性会降到最低。当然,我们都知道没有 100% 安全的系统;目标必须是最大限度地降低和管理风险。Postfix 绝对是为最大限度地降低安全风险而设计的。

  • 简单性和兼容性。 Postfix 的编写方式使其“从头开始”设置只需五分钟。当您想要替换 sendmail 或其他 MTA 时,情况会更好:默认情况下,postfix 可以使用旧的配置文件!

  • 稳健性和稳定性。 Postfix 的编写考虑到了邮件网络的某些组件(局域网、互联网上行链路、本地接口等)偶尔会发生故障的预期。通过预测任何给定事务的任一端可能出错的事情,postfix 能够在许多(如果不是大多数)情况下保持服务器正常运行。例如,如果邮件无法送达,则会安排稍后送达,而不会立即启动持续重试。

postfix 的稳定性和速度的一个关键贡献因素是其智能的邮件排队方式。Postfix 使用四个不同的队列,每个队列的处理方式都不同(见图 1)

Using Postfix for Secure SMTP Gateways

图 1. Postfix 队列

  • Maildrop 队列。在系统本地传递的邮件在 Maildrop 队列中被接受。在这里,邮件在被移交给 Incoming 队列之前,会检查其格式是否正确(并在必要时进行修复)。

  • Incoming 队列。Incoming 队列接收来自其他主机、客户端或 Maildrop 队列的邮件。只要电子邮件仍在到达并且只要 postfix 尚未真正处理电子邮件,此队列就是保存电子邮件的位置。

  • Active 队列。Active 队列是用于实际传递消息的队列,因此发生错误的潜在风险最大。此队列的大小有限,并且只有在有空间时才会接受消息。这意味着 Incoming 队列和 Deferred 队列中的电子邮件必须等到 Active 队列可以接受它们。

  • Deferred 队列。无法送达的电子邮件会被放入 Deferred 队列。这可以防止系统不断尝试传递电子邮件,并使 Active 队列尽可能短,以便为较新的消息提供优先级。这也有助于提高稳定性。如果 MTA 无法到达某个域,则该域的 所有 电子邮件都会放入 Deferred 队列,以便这些消息不会不必要地占用系统资源。重试的计划等待时间会越来越长。当等待时间到期时,电子邮件会再次放入 Active 队列进行传递;系统会跟踪重试历史记录。

Postfix 懒人模式:快速而简陋的启动过程

现在是您一直等待(或直接跳过)的部分:postfix 设置。与 sendmail 类似,postfix 使用“.cf”文本文件作为其主要配置文件,称为 main.cf。但是,postfix 中的“.cf”文件使用简单的“parameter=$value”语法。更重要的是,这些文件注释非常完善,并且使用了高度描述性的变量名。

事实上,如果您的电子邮件需求足够简单,您可能可以通过编辑 main.cf 并边阅读其注释边弄清楚您需要了解的大部分内容。

对于许多用户来说,这就是在 SMTP 网关上配置 postfix 所需做的全部工作

  1. 通过本地软件包工具(rpm 等)从二进制软件包安装 postfix,或从源代码编译并运行 postfix 的 INSTALL.sh 脚本。

  2. 使用您选择的文本编辑器打开 /etc/postfix/main.cf。

  3. 取消注释并设置参数 myhostname 等于您服务器的完全限定域名 (FQDN),例如,“myhostname = buford.dogpeople.org”。

  4. 取消注释并按如下方式设置参数 mydestination,假设这是您整个域的电子邮件网关

mydestination = $myhostname, localhost.$mydomain, $mydomain

注意:请逐字输入以上行。

  1. 保存并关闭 main.cf。

  2. 如果需要,在 /etc/aliases 中添加一行,将 root 的邮件转移到权限较低的帐户,例如 root: mick。这也是映射由内部邮件服务器服务的用户的别名的地方(例如,mick.bauer: mbauer@secretserver.dogpeople.org)。完成编辑和/或添加别名后,保存文件并输入命令 newaliases 以将其转换为哈希数据库。

  3. 执行命令 postfix start

我们刚刚取得了什么成就?仅需四个步骤,我们就为我们的机器及其本地域名安装、配置并启动了 SMTP 服务。如果这台机器是防火墙或防火墙 DMZ 网络上的 SMTP 网关,则本地用户现在可以使用它来路由出站电子邮件,并且可以通过我们域的“MX”DNS 记录指向它(即,它可以向外界宣传为我们域的邮件服务器)。我们还告诉它直接处理(而不是转发)寻址到本地主机的邮件。对于大约五分钟的打字投资来说,回报相当不错,不是吗?

(注意:虽然这可能足以让 postfix 工作,但这 不足以 保护它。请不要停止阅读!)

快速而简陋的解释

虽然这很酷,但可能不足以让 postfix 完成您的网络需要完成的工作。即使足够了,您也应该深入挖掘:无知几乎总是会导致糟糕的安全性。让我们仔细看看我们刚刚做了什么,然后继续进行更巧妙的 postfix 技巧。

首先,为什么需要在 main.cf 中输入如此少的信息?我们添加到其中的唯一内容是我们的完全限定域名。事实上,根据您的机器配置方式,甚至可能没有必要提供

这是因为 postfix 使用诸如 gethostname 之类的系统调用,以尽可能多地直接从您的内核中收集信息。如果给定您主机的完全限定域名,它会足够智能地知道第一个“.”之后的所有内容都是您的域名,并相应地设置变量 mydomain

如果您的服务器有多个 FQDN(即,您域的 DNS 中有多个“A”记录),您可能需要在 mydestination 中添加其他名称。例如,如果您的 SMTP 网关兼作您的公共 FTP 服务器,因此除了其正常主机名之外,还具有与之关联的名称“ftp”,则您的 mydestination 声明可能如下所示

mydestination = $myhostname, localhost.$mydomain, ftp://www.$mydomain, $mydomain

重要的是,您的服务器可以合法引用的 任何名称 都包含在此行中。

我们在“快速而简陋”的过程中还做了另外两件有趣的事情。一个是使用命令 postfix start 启动 postfix。正如 BIND 使用 ndc 来控制构成 BIND 的各种进程一样,postfix 命令可用于管理 postfix。与 BIND 类似,postfix 实际上是一套命令、守护程序和脚本,而不是单个单体程序。

postfix 命令最常见的调用是 postfix start、postfix stoppostfix reload。启动和停止是显而易见的;reload 使 postfix 重新加载其配置文件,而无需停止和重新启动。另一个方便的命令是 postfix flush,它强制 postfix 立即尝试发送所有排队的消息。这在更改您认为可能导致问题的设置后特别有用——如果您的更改有效,则所有因问题延迟的消息都会立即发送出去。无论如何它们都会发送出去,但不会那么快。

我们做的另一件事是在 /etc/aliases 中添加一行,将 root 的电子邮件转移到非特权帐户。这是一个很好的健康偏执:我们不希望必须以超级用户身份登录来执行诸如查看系统报告之类的日常活动,这些报告有时会通过电子邮件发送给 root。但是,请注意:如果您的非特权帐户使用“.forward”文件将您的邮件转发到其他系统,您可能会最终通过公共带宽以明文形式发送管理消息!

别名揭秘

正如在快速而简陋的过程中提到的那样,别名也适用于映射实际上在 SMTP 网关上没有帐户的用户的电子邮件地址。这种做法有两个主要好处。首先,大多数用户更喜欢有意义的电子邮件名称和简短的主机/域名,例如,“john.smith@acme.com”而不是“jsmith023@mail77.midwest.acme.com”。其次,您可能不希望您的用户连接到公共可访问的服务器并在其上存储邮件。同样,常识告诉我们,任何未经过滤的人群可以交流的服务器都必须保持距离。公共服务器和私有服务器之间的隔离越大越好。(并且不要忘记,POPmail 密码是以明文形式传输的!)

aliases 的另一个用途是维护邮件列表。别名不仅可以指向地址或逗号分隔的地址列表,还可以指向邮件列表。这是通过 :include: 标签实现的——如果没有这个标签,postfix 将 追加 邮件到指定的文件,而不是使用该文件来获取收件人。(这是一个功能,而不是一个错误;有时将某些类型的消息写入文本文件而不是邮箱很有用。)

以下是示例别名文件的一部分,其中包含所有这些类型的映射

postmaster:     root
mailer-daemon:  root
hostmaster:     root
root:           bdewinter
mailguys:       bdewinter,mick.bauer
mick.bauer:     mbauer@biscuit.stpaul.dogpeople.org
clients:        :include:/etc/postfix/clientlist.txt
spam-reports:   /home/bdewinter/spambucket.txt

一个警告:如果别名指向不同的邮件服务器,则该服务器必须属于 SMTP 网关配置为中继邮件的域(即,该服务器的 FQDN 或其域必须列在 main.cf 中的 mydestination 声明中)。

每当您编辑别名时,都不要忘记运行 newaliases,或者更时髦的 postalias /etc/aliasespostalias 命令更时髦,因为它可以接受 任何 格式正确的别名文件作为其输入。这两个命令都将别名文件压缩为数据库文件,每次解析目标地址时都可以重复且快速地搜索该文件;postfix 和 sendmail 都不直接使用 aliases 的文本版本。

如果您有大量用户和/或内部邮件服务器,别名文件更新适合自动化,尤其是在通过安全外壳 (ssh) 和安全复制 (scp) 的情况下。使用带有空密码短语 RSA(或 DSS/El Gamal)密钥的 scp,您的内部邮件服务器可以定期将其本地别名文件复制到 SMTP 网关,然后 SMTP 网关可以将它们合并到新的 /etc/aliases 中,然后执行 postalias /etc/aliases。(不幸的是,准确地告诉您 如何 使用 scp/ssh 超出了本文的范围。)这种做法在大型组织中尤其有用,在这些组织中,不同的人控制着不同的邮件服务器:日常电子邮件帐户管理可以保持分散化。

阻止未经请求的商业电子邮件

垃圾邮件是最常见和最令人讨厌的电子邮件滥用类型之一。Postfix 通过 main.cf 中的几个设置提供针对 UCE(未经请求的商业电子邮件)的保护。但是,需要谨慎:垃圾邮件和合法传播之间存在一条细微的界限,即使是适度的 UCE 控制也完全有可能导致某些合法(即,所需的)邮件被丢弃。

话虽如此,对于大多数站点来说,这是一个可以接受的风险(也可以通过最终用户教育来避免),我们建议您 至少 在 main.cf 中设置以下内容

  • smtpd_recipient_limit。此设置指示单个消息的标头中可以寻址多少收件人。通常,这样的数字不应超过 500 左右。收到一封有 500 个收件人且未发送到邮件列表的电子邮件将是极端的。

  • smtpd_recipient_restricitons。并非到达您服务器的每封电子邮件都应该被接受。此参数指示 postfix 根据一个或多个条件检查每个消息的收件人地址库。最容易维护的之一是 access 数据库。此文件列出了允许从您的服务器接收邮件的域、主机、网络和用户。要启用它:(1)设置 check_recipient_access = hash:access;(2)创建 /etc/postfix/access(执行 man 5 access 以获取格式/语法);以及(3)运行 postmap hash:/etc/postfix/access 以将文件转换为数据库。每次编辑 /etc/postfix/access 时,重复步骤 (3)。

  • smtpd_sender_restrictions。默认情况下,postfix 将接受来自所有人的 SMTP 连接,这可能会使您的服务器暴露于 SMTP 中继,UCE 肇事者经常使用这种方法来隐藏其身份,方法是将其消息从毫无戒心的 SMTP 中继器“反弹”出去。如果发生这种情况,其他服务器很可能甚至很有可能拒绝来自您的域的电子邮件。其他保护机制在于始终明智地针对 DNS 检查发件人。尽管这会降低一些性能,但它使从错误的发件人电子邮件地址发送信息变得更加困难。有关此参数的可能列表选项列表,请参阅文件 /etc/postfix/sample-smtpd.cf。请注意,hash:access 是其中之一;access 数据库不仅可以用于允许/禁止特定收件人,还可以用于允许/禁止发件人。有关反 UCE 参数及其确切语法的完整列表,请参阅 /etc/postfix/sample-smtpd.cf。

通过地址伪装隐藏内部电子邮件地址

为了防止泄露对合法的外部方没有用途的信息,明智的做法是在 main.cf 文件中设置参数 masquerade_domains = $mydomain(请记住,“$mydomain”是指变量)。如果您希望为“root”发送的邮件(可能是一个好主意)创建一个例外,您可以设置参数 masquerade_exceptions = root。这将导致从出站邮件的“发件人”地址中的 FQDSes 中删除内部主机名。

在 chroot Jail 中运行 Postfix

现在我们来讨论我们可以用来保护 postfix 的更酷的事情之一:在“chroot jail”中运行它。chroot 是一个 UNIX 命令,它将“chrooted”进程限制在指定的目录中;该目录成为该进程的“/”。这通常需要您首先创建进程所需但在其他地方正常保存的事物的副本。例如,如果进程在启动时查找“/etc/mydaemon.conf”,但被 chrooted 到“/var/mydaemon”,则进程实际上将查找“/var/mydaemon/etc/mydaemon.conf”。

chrooting 的优势应该是显而易见的:如果 chrooted-postfix 进程以某种方式被劫持,攻击者会发现自己身处“软禁室”,从中(希望)无法访问任何敏感或重要的系统文件或数据。这不是万能药,但它显着提高了利用 postfix 的难度。

令人高兴的是,chroot postfix 所需的准备工作在 postfix 文档的子目录“examples”中提供。这些文件实际上不是 shell 脚本:它们是建议的命令序列。

更好的是,postfix 的某些二进制发行版具有安装脚本,可以在安装 postfix 后自动为您进行这些准备工作。例如,在 SuSE 中,postfix RPM 软件包运行一个脚本,该脚本在 /var/spool/postfix 中创建一个完整的目录树,供 postfix 在 chrooted 时使用(etc、usr、lib 等),并具有适当的所有权和权限。

除了“配置”postfix 的 chroot jail 之外,您还需要编辑 /etc/postfix/master.cf 以切换您希望 chrooted 运行的 postfix 守护程序(即,在要 chrooted 的每个守护程序的“chroot”列中放入“y”)。但是,不要 对“command”列指示其类型为“pipe”或“local”的守护程序执行此操作。某些二进制软件包发行版会在 postfix 安装期间自动切换适当的守护程序以进行 chroot(同样,SuSE 会这样做)。

在配置 chroot jail 并编辑 master.cf 后,您需要做的就是像往常一样启动 postfix:postfix start。Postfix 的主进程处理实际的 chroot-ing。

结论

这些信息足以让您入门。愿您的邮件及时到达,垃圾邮件污秽远离!

资源

Using Postfix for Secure SMTP Gateways
Mick Bauer 是 ENRGI 明尼阿波利斯分部的安全实践主管,ENRGI 是一家网络工程和咨询公司。自 1995 年以来,他一直是 Linux 的爱好者,自 1997 年以来一直是 OpenBSD 的狂热者,特别喜欢让这些尖端的操作系统在过时的垃圾硬件上运行。Mick 欢迎发送至 mick@visi.com 的问题、评论和问候。

Using Postfix for Secure SMTP Gateways
Brenno de Winter,28 岁,是 De Winter Information Solutions 的总裁,专注于 Linux。他从九岁开始编程。在他的日常工作中,他参与 UNIX/Linux、数据库、安全、基于 IP 的语音演示、咨询和培训。他活跃于 Polder Linux 用户组,为包括 GnuPG、MySQL 和 TWIG 在内的多个 GPL 项目做出了贡献,并且正在创建自己的一个全新项目。
加载 Disqus 评论