我正在采取措施强化我的外发 postfix SMTP 服务器。我想防止用户伪造他们的发件人地址。
使用 Postfix SMTP 发送电子邮件时,可以通过三种方式识别发件人:
- 电子邮件本身有一个
From:
标题 - 定义在RFC 822 - 使用 SMTP 发送时,有一个
MAIL FROM
地址 - 定义在RFC 821 - 登录 Postfix (SMTP) 时,客户端指定一个用户名,该用户名也可以解释为发件人
查看手册,我相信拒绝发送者登录不匹配和拒绝未列出的发件人将共同保证MAIL FROM
电子邮件与 postifx 登录相关联。这就是上面的 2 和 3 匹配。
我不知道如何确保三者都匹配。如果结果只是重写消息而不是拒绝,我会很高兴,但两者都可以。然而,我看不出有什么办法可以做到这一点。我明白清理将添加一个丢失的From:
标题,但我看不到任何方法可以检查并重写它。
感谢那些指出另一个类似的问题。不幸的是,这没有帮助,因为问题有两个答案,一个非常模糊,另一个似乎是错误的。
答案1
我花了一些时间研究这个问题,但找不到一种纯粹的后缀方法。建议使用的方法header_checks
似乎不起作用,因为你不能(据我所知)将一个标题与另一个标题进行匹配。
可以编写自己的程序/脚本来为您执行检查,并将其用作内容过滤器。
步骤1
下面是我用 Python 编写的简化版本。它从 stdin 读取电子邮件,MAIL from
并将RECPT to
地址作为参数。它检查From:
邮件头,MAIL from
如果不匹配,则替换它。我将其保存为/usr/share/mail_filter/filter.py
:
#! /usr/bin/python3
import sys
import subprocess
import email.parser
import email.policy
parser = email.parser.BytesParser(policy=email.policy.default)
message = parser.parse(sys.stdin.buffer)
envelope_from = sys.argv[1]
envelope_to = sys.argv[2]
# This if statement checks envelope from against message from
if message['From'].addresses[0].addr_spec != envelope_from:
print(f"Replacing sender {message['from']} with {envelope_from}", file=sys.stderr)
message.replace_header('From', envelope_from)
# sendmail -G -i -f sender@sender_domain.tld recipient@recipient_domain.tld
sendmail = subprocess.Popen(["/usr/sbin/sendmail", "-Gif", envelope_from, envelope_to], stdin=subprocess.PIPE)
with sendmail.stdin:
sendmail.stdin.write(message.as_bytes())
# If sendmail returns an error, cascade it back to postfix
sys.exit(sendmail.wait())
第2步
更新/etc/postfix/master.cf
:
# added the -o content_filter...
smtp inet n - y - - smtpd
-o content_filter=filter:dummy
# Added this entire service
filter unix - n n - 10 pipe
flags=Rq user=filter null_sender=
argv=/usr/share/mail_filter/filter.py ${sender} ${recipient}
请注意,这引用了步骤 1 中的脚本位置和步骤 3 中定义的用户
步骤3
filter
我在一个组中添加了一个具有使用权限的OS 用户sendmail
。
useradd --system --gid postdrop filter
注意事项
根据指示简单过滤器(使用 传递sendmail
)只能应用于 SMTP 客户端,无法过滤通过 sendmail 发送的消息。如果这对您来说是个问题,那么您需要编写一个高级内容过滤器。