跳转到主要内容

于 2025年04月22日 摘录自 Postfix SMTP relay and access control

简介

Postfix SMTP 服务器从网络接收邮件,并暴露在垃圾邮件和病毒的威胁之下。本文档介绍了 Postfix 用于控制接受哪些 SMTP 邮件的内置和外部方法,以及如何避免常见错误和测试配置。

本文档涵盖的主题:

中继控制、垃圾邮件控制及用户级策略 

在很久以前,互联网是一个友好的环境。邮件服务器会愉快地代表任何人将邮件转发到任何目的地。在今天的互联网中,垃圾邮件发送者滥用转发邮件的服务器,这些被滥用的服务器最终会被列入反垃圾邮件黑名单。例如,请参阅http://www.mail-abuse.org/和其他网站上的信息。

默认情况下,Postfix 对邮件中继采取了适度严格的策略。Postfix 仅转发来自受信任网络的客户端、通过 SASL 认证的客户端,或发往配置为授权中继目的地的域的邮件。有关默认邮件中继策略的详细描述,请参阅 smtpd_relay_restrictions 参数,以及该参数所引用的相关信息。

注意:Postfix 2.10 之前的版本不包含 smtpd_relay_restrictions。这些设置已被合并到 smtpd_recipient_restrictions 中。这可能导致意外结果。例如,一个宽松的垃圾邮件拦截策略可能会意外导致一个宽松的邮件中继策略。此问题的示例在"smtpd_recipient_restrictions 的危险用法"中有所记录。

Postfix SMTP 服务器的大多数访问控制旨在阻止垃圾邮件。

  • 协议导向:部分 SMTP 服务器访问控制通过严格遵守 SMTP 协议来阻止邮件;这些控制措施可捕获实现不佳或配置不当的垃圾邮件软件,以及携带自定义非标准 SMTP 客户端实现的邮件蠕虫。随着垃圾邮件发送者和蠕虫作者逐渐掌握 RFC 文档,协议导向的访问控制效果会逐渐减弱。
  • 基于黑名单:部分 SMTP 服务器访问控制会查询已知恶意网站(如开放邮件中继、开放网页代理、被黑客远程控制的个人电脑等)的黑名单。这些黑名单的有效性取决于其完整性和更新频率。
  • 阈值导向:部分 SMTP 服务器访问控制通过提高门槛来增强安全性,具体方式包括让客户端执行更多操作(灰名单)或请求二次验证(SPF 和发件人/收件人地址验证)。灰名单和SPF策略在外部实现,相关内容详见SMTPD_POLICY_README文档。发件人/收件人地址验证是ADDRESS_VERIFICATION_README文档的主题。

遗憾的是,所有垃圾邮件控制措施都可能错误地拒绝合法邮件。这对于拥有多种类型用户的站点而言可能是个问题。对于部分用户而言,任何垃圾邮件的漏网都不可接受;而对于其他用户而言,单封合法邮件被阻挡便会造成严重影响。由于不存在适用于所有用户的"万能"策略,Postfix 支持为不同用户配置不同的 SMTP 访问限制。这在RESTRICTION_CLASS_README文档中有所描述。

适用于所有SMTP邮件的限制 

除了可以在下一节中描述的按客户端或按用户配置的限制外,Postfix 还实现了几个适用于所有 SMTP 邮件的限制。

  • 内置的 header_checksbody_checks 内容限制,如 BUILTIN_FILTER_README 文档中所述。这发生在 Postfix 接收邮件时,在邮件存储到 incoming queue 之前。
  • 外部队列前内容限制,如在 SMTPD_PROXY_README 文档中所述。这发生在 Postfix 接收邮件时,在邮件存储到 incoming queue 之前。
  • 要求客户端在发送 MAIL FROM 或 ETRN 命令之前发送 HELO 或 EHLO 命令。这可能导致自定义应用程序发送邮件时出现问题。因此,此要求默认禁用("smtpd_helo_required = no")。
  • 禁止在 MAIL FROM 或 RCPT TO 命令中使用非法语法。这可能导致自定义邮件发送应用程序以及老旧的 PC 邮件客户端出现问题。出于此原因,该要求默认禁用("strict_rfc821_envelopes = no")。
  • 拒绝来自不存在的发件人地址的邮件。此类出站过滤有助于减缓蠕虫和其他恶意软件的传播,但可能导致使用不可回复地址发送邮件的自建软件出现问题。出于此原因,该要求默认禁用("smtpd_reject_unlisted_sender = no")。
  • 拒绝发往不存在的收件人地址的邮件。此类入口过滤机制有助于防止邮件队列中出现无法投递的MAILER-DAEMON消息。此要求默认启用("smtpd_reject_unlisted_recipient = yes")。

通过 SMTP 访问限制列表实现选择性控制 

Postfix 允许您为 SMTP 对话的每个阶段指定访问限制列表。具体限制项在 postconf(5) 手册页中描述。

简单限制列表示例:

/etc/postfix/main.cf:
# 仅允许来自受信任网络的连接。
smtpd_client_restrictions = permit_mynetworks, reject
# 不要与不知道自己主机名的邮件系统通信。
# 在 Postfix 2.3 之前,请指定 reject_unknown_hostnamesmtpd_helo_restrictions = reject_unknown_helo_hostname
# 不接受来自不存在的域的邮件。
smtpd_sender_restrictions = reject_unknown_sender_domain
# 垃圾邮件控制:排除本地客户端和经过身份验证的客户端
# 通过 DNSBL 查询。
smtpd_recipient_restrictions = permit_mynetworks, 
permit_sasl_authenticated,
# reject_unauth_destination 在此处无需设置,如果邮件
# 转发策略已在 smtpd_relay_restrictions
# 中指定(Postfix 2.10 及更高版本可用)。
reject_unauth_destination
reject_rbl_client zen.spamhaus.org,
reject_rhsbl_reverse_client dbl.spamhaus.org,
reject_rhsbl_helo dbl.spamhaus.org,
reject_rhsbl_sender dbl.spamhaus.org
# 中继控制(Postfix 2.10 及更高版本):本地客户端和
# 经过身份验证的客户端可以指定任何目标域。
smtpd_relay_restrictions = permit_mynetworks, 
permit_sasl_authenticated,
reject_unauth_destination
# 阻止过早发送请求的客户端。
smtpd_data_restrictions = reject_unauth_pipelining
# 通过策略服务调用强制执行邮件体积配额。
smtpd_end_of_data_restrictions = check_policy_service unix:private/policy

每个限制列表从左到右依次评估,直到某个限制产生 PERMIT、REJECT 或 DEFER(稍后重试)的结果。每个列表的末尾等同于 PERMIT 结果。通过在 REJECT 限制前放置 PERMIT 限制,可以为特定客户端或用户设置例外。这称为白名单;上文的 smtpd_relay_restrictions 示例允许来自本地网络和 SASL 认证客户端的邮件,但拒绝发往任意目的地的邮件。

下表总结了每个 SMTP 访问限制列表的用途。所有列表使用完全相同的语法;它们仅在评估时间以及 REJECT 或 DEFER 结果的影响方面有所不同。

限制列表名称版本状态REJECT 或 DEFER 结果的影响
smtpd_client_restrictions全部可选拒绝所有客户端命令
smtpd_helo_restrictions所有可选拒绝 HELO/EHLO 信息
smtpd_sender_restrictions所有可选拒绝 MAIL FROM 信息
smtpd_recipient_restrictions≥ 2.10如果 smtpd_relay_restrictions 未强制执行中继策略,则必填拒绝 RCPT TO 信息
< 2.10必填
smtpd_relay_restrictions≥ 2.10如果 smtpd_recipient_restrictions 未强制执行中继策略,则必填拒绝 RCPT TO 信息
< 2.10不可用
smtpd_data_restrictions≥ 2.0可选拒绝 DATA 命令
smtpd_end_of_data_restrictions≥ 2.2可选拒绝 END-OF-DATA 命令
smtpd_etrn_restrictions所有可选拒绝 ETRN 命令

延迟评估 SMTP 访问限制列表 

早期版本的 Postfix 会尽早评估 SMTP 访问限制列表。在 Postfix 发送 "220 $myhostname..." 欢迎信息之前,Postfix 会评估客户端访问限制列表;在 Postfix 响应 HELO(EHLO)命令之前,会评估 helo 限制列表;在 Postfix 响应 MAIL FROM 命令之前,会评估发件人限制列表,依此类推。这种方法被证明难以使用。

当前 Postfix 版本将客户端、HELO 和发件人限制列表的评估推迟到 RCPT TO 或 ETRN 命令执行时。此行为由 smtpd_delay_reject 参数控制。限制列表仍按正确的顺序(client、helo、etrn)或(client、helo、sender、relay、recipient、data 或 end-of-data)进行评估。当某个限制列表(例如 client)评估结果为 REJECT 或 DEFER 时,后续的限制列表(例如 helo、sender 等)将被跳过。

在引入smtpd_delay_reject参数的同时,Postfix还进行了修改以支持混合限制列表,这些列表结合了客户端、helo、发件人、收件人或etrn命令的相关信息。

延迟限制评估的优势,以及混合限制的优势:

  • 部分 SMTP 客户端不期望在 SMTP 会话早期收到负面响应。当负面信息被推迟至 RCPT TO 响应时,客户端会按预期离开,而非一直等待超时,或更糟糕地陷入无限连接-拒绝-连接循环。
  • Postfix 可以记录更有用的信息。例如,当 Postfix 拒绝客户端名称或地址并延迟操作至 RCPT TO 命令时,它可以记录发件人和收件人地址。这比仅记录客户端主机名和 IP 地址且不知被阻塞邮件的所属者更为有用。
  • 混合使用是复杂允许列表策略的必要条件。例如,为了拒绝非本地客户端发送的邮件中的本地发件人地址,您需要能够在同一限制列表中混合使用对客户端信息和发件人信息的限制。没有此功能,许多基于用户的访问限制将无法实现。

smtpd_recipient_restrictions 的危险用法 

到目前为止,读者可能在想,既然对 smtpd 客户端、helo 或发件人的限制评估被推迟到 RCPT TO 或 ETRN 命令时,为什么我们还需要这些限制。有些人建议将所有访问限制都放在smtpd_recipient_restrictions列表中。不幸的是,这可能导致访问权限过于宽松。这是如何可能的?

smtpd_recipient_restrictions 功能的目的是控制 Postfix 如何响应 RCPT TO 命令。如果限制列表评估为 REJECT 或 DEFER,则拒绝收件人地址;这里没有意外。如果结果为 PERMIT,则收件人地址被接受。而这里可能出现意外情况。

问题在于,Postfix 2.10 之前的版本没有 smtpd_relay_restrictions。它们将邮件中继和垃圾邮件阻止策略合并到了smtpd_recipient_restrictions中。结果是,一个宽松的垃圾邮件阻止策略可能会意外导致一个宽松的邮件中继策略。

以下是一个示例,展示了当 PERMIT 结果导致过多访问权限的情况:

1 /etc/postfix/main.cf:
2 smtpd_recipient_restrictions = 
3 permit_mynetworks
4 check_helo_access hash:/etc/postfix/helo_access
5 reject_unknown_helo_hostname
6 reject_unauth_destination
7
8 /etc/postfix/helo_access:
9 localhost.localdomain PERMIT

第 5 行拒绝来自未在 HELO 命令中指定正确主机名的宿主机的邮件(在 Postfix 2.3 之前,需指定 reject_unknown_hostname)。第4行和第9行对以"HELO localhost.localdomain"进行自我声明的机器做出例外处理,允许其发送邮件。

此配置的问题在于,smtpd_recipient_restrictions 会将所有自报为 "localhost.localdomain" 的主机视为允许,导致 Postfix 成为此类主机的开放中继。

在 Postfix 2.10 版本之前,您应将非收件人限制规则放置在 reject_unauth_destination 限制规则之后,而非之前。在上述示例中,基于 HELO 的限制应放置在 reject_unauth_destination之后,或者更好是将基于 HELO 的限制放在 smtpd_helo_restrictions 部分,这样它们就不会产生影响。

1 /etc/postfix/main.cf:
2 smtpd_recipient_restrictions = 
3 permit_mynetworks
4 reject_unauth_destination
5 check_helo_access hash:/etc/postfix/helo_access
6 reject_unknown_helo_hostname
7
8 /etc/postfix/helo_access:
9 localhost.localdomain PERMIT

上述错误在 Postfix 2.10 及更高版本中不会出现,因为中继策略已在 smtpd_relay_restrictions,而垃圾邮件阻止策略在smtpd_recipient_restrictions下指定。然后,宽松的垃圾邮件阻止策略不会导致宽松的邮件中继策略。

SMTP 访问规则测试 

Postfix 提供了多个功能,有助于测试 SMTP 访问规则:

soft_bounce

这是一个安全网,将 SMTP 服务器 REJECT 操作转换为 DEFER(稍后重试)操作。这会将本应被退回发件人的邮件保留在队列中。在 main.cf 文件中,以防止 Postfix SMTP 服务器永久拒绝邮件,并将所有 5xx SMTP 响应代码更改为 4xx。

warn_if_reject

当放置在拒绝类型限制、访问表查询或 check_policy_service 查询之前,这会记录一条 "reject_warning" 消息,而不是拒绝请求(当拒绝类型限制因临时错误失败时,这会为任何隐含的 "defer_if_permit" 操作,这些操作通常会阻止邮件被后续访问限制接受)。此功能对 defer_if_reject 限制无效。

XCLIENT

通过此功能,授权的 SMTP 客户端可以模拟其他系统并执行真实的 SMTP 访问规则测试。在 XCLIENT_README 文档末尾提供了模拟其他系统进行访问规则测试的示例。