正如在 仅接受真实用户的退信 中讨论的那样,现在存在一个漏洞,使我们无法捕获发送给系统用户和别名的虚假 投递状态通知,例如postmaster. 在这里,我们介绍两种替代方法,以确保仅为实际发送外发邮件的用户接受退信。
第一种方法在 acl_rcpt_to ACL 中执行。在这里,我们检查收件人地址是否对应于本地邮箱
# Deny mail for users that do not have a mailbox (i.e. postmaster, # webmaster...) if no sender address is provided. These users do # not send outgoing mail, so they should not receive returned mail. # deny message = This address never sends outgoing mail. \ You are responding to a forged sender address. log_message = bogus bounce for system user <$local_part@$domain> senders = : postmaster@* domains = +local_domains !mailbox check |
不幸的是,我们如何执行邮箱检查将取决于您如何投递邮件(与之前一样,我们提取收件人地址中第一个 "=" 符号之前的部分,以适应 信封发件人签名)
如果邮箱映射到您服务器上的本地用户帐户,我们可以检查收件人名称是否映射到与您系统上的 "regular" 用户对应的用户 ID,例如在 500 - 60000 范围内
set acl_m9 = ${extract{1}{=}{${lc:$local_part}}} set acl_m9 = ${extract{2}{:}{${lookup passwd {$acl_m9}{$value}}}{0}} condition = ${if and {{>={$acl_m9}{500}} {<${acl_m9}{60000}}} {true}} |
如果您将邮件投递到 Cyrus IMAP 套件,您可以使用提供的 mbpath 命令行实用程序来检查邮箱是否存在。您需要确保 Exim 用户有权检查邮箱(例如,您可以将其添加到cyrus组:# adduser exim4 cyrus)。
set acl_m9 = ${extract{1}{=}{${lc:$local_part}}} condition = ${run {/usr/sbin/mbpath -q -s user.$acl_m9} {true}} |
如果您将所有邮件转发到远程计算机进行投递,您可能需要执行 收件人回拨验证,并让该计算机决定是否接受邮件。您需要在回拨中保持原始信封发件人不变
verify = recipient/callout=use_sender |
由于在本地投递邮件的情况下,此邮箱检查重复了路由器中执行的某些逻辑,并且由于它特定于我们站点的邮件投递机制,因此对于我们中的完美主义者来说,这可能有点笨拙。因此,我们现在将提供另一种替代方法。
您可能有一个名为system_aliases或类似的路由器,用于重定向发送给如下用户的邮件postmaster和mailer-demon. 通常,这些别名不用于外发邮件的发件人地址。因此,您可以通过向路由器添加以下条件来确保传入的 投递状态通知 不会通过它路由
!senders = : postmaster@* |
一个别名路由器的示例现在可能如下所示
system_aliases: driver = redirect domains = +local_domains !senders = : postmaster@* allow_fail allow_defer data = ${lookup{$local_part}lsearch{/etc/aliases}} user = mail group = mail file_transport = address_file pipe_transport = address_pipe |
尽管我们现在阻止了发送到某些系统别名的退信,但其他别名只是在影子化现有的系统用户(例如 "root"、"daemon" 等)。如果您通过accept驱动程序投递本地邮件,并使用check_local_user来验证收件人地址,您现在可能会发现自己将邮件直接路由到这些系统帐户。
为了解决这个问题,我们现在想在处理您的本地邮件(例如 local_user)的路由器中添加一个额外的条件,以确保收件人不仅存在,而且是 "regular" 用户。例如,如上所述,我们可以检查用户 ID 是否在 500 - 60000 范围内
condition = ${if and {{>={$local_user_uid}{500}}\ {<{$local_user_uid}{60000}}}\ {true}} |
一个用于本地投递的路由器示例现在可能如下所示
local_user: driver = accept domains = +local_domains check_local_user condition = ${if and {{>={$local_user_uid}{500}}\ {<{$local_user_uid}{60000}}}\ {true}} transport = transport |
请注意,如果您实施此方法,您的服务器对系统用户的虚假退信的拒绝响应将与对未知收件人的拒绝响应相同(在我们的例子中为 550 Unknown User)。