Postfix中能否让reject_unknown_helo_hostname在permit_sasl_authenticated前生效?如何提前拒绝未知主机的SASL登录尝试?
这个问题太典型了——很多用Postfix做中继的朋友都会踩这个坑:明明加了HELO限制,恶意IP还是能凑上来试SASL登录,感觉自己的限制像“摆设”。其实核心问题出在Postfix的限制执行时机和你的规则匹配逻辑上,咱们一步步拆解解决:
先搞懂你为啥拦不住:两个核心坑点
1. 默认开启的「延迟拒绝」让限制检查“迟到”
Postfix默认有个smtpd_delay_reject = yes的配置,这个参数会把所有非连接阶段的限制(包括HELO、收件人限制等)延迟到客户端发送第一个RCPT TO命令之后才执行。
你遇到的恶意客户端根本不会发RCPT TO——他们的目标就是试SASL登录,发完EHLO、STARTTLS、AUTH就跑路了,所以你的reject_unknown_helo_hostname根本没机会触发检查,自然拦不住。
2. 你的HELO规则不匹配对方的攻击姿势
看你Wireshark抓的包,对方发的是EHLO [182.150.23.17]——这是RFC合规的HELO格式(允许用IP地址当HELO标识,用方括号包裹)。而reject_unknown_helo_hostname的作用是拒绝无法反向解析到客户端IP的主机名,这种带方括号的IP地址Postfix会直接判定为“合法有效”,不会触发拒绝。
再加上你smtpd_client_restrictions最后加了permit,等于给所有没被前面规则拦住的IP开了“绿色通道”,哪怕反向解析失败也能继续走流程。
解决办法:三步把恶意请求拦在认证前
第一步:关掉延迟拒绝,让限制“实时生效”
打开Postfix的main.cf,把延迟拒绝关掉:
smtpd_delay_reject = no
这个参数改成no后,Postfix会在对应的SMTP阶段立即执行限制检查:比如HELO规则会在客户端发完EHLO/HELO后马上校验,不符合就直接断开连接,根本到不了AUTH步骤。
第二步:强化HELO规则,精准拦截IP式HELO
把你的smtpd_helo_restrictions改成下面这样,专门拦用IP当HELO的请求:
smtpd_helo_restrictions = permit_mynetworks, reject_non_fqdn_helo_hostname, reject_invalid_helo_hostname, reject_unknown_helo_hostname, reject_helo_ip_addresses=all
- 最前面的
permit_mynetworks保证你自己的合法客户端不受影响; reject_helo_ip_addresses=all是关键:直接拒绝所有用IP地址(不管带不带方括号)当HELO的请求,正好命中你遇到的这种botnet攻击;- 剩下的规则继续拦截格式非法、无法解析的HELO主机名。
第三步:修正客户端限制,去掉冗余的permit
把smtpd_client_restrictions最后那个permit删掉,改成更严格的规则:
smtpd_client_restrictions = permit_mynetworks, reject_unknown_client_hostname, reject_rbl_client zen.spamhaus.org, # 可选:加个RBL拦已知恶意IP reject
去掉permit后,所有不在你的信任网络、反向解析失败的IP,会在连接阶段就被直接断开,连EHLO都发不出来。加RBL是额外的buff,能提前挡住90%以上的已知恶意IP。
最后:验证配置并重启
先检查配置有没有语法错误:
postfix check
如果没报错,重启Postfix让配置生效:
systemctl reload postfix
额外补充:Postfix限制的执行顺序(必记)
给你理清楚Postfix各个限制组的执行时机,以后改配置就不会踩坑:
- smtpd_client_restrictions:连接建立后立即执行(最早的检查)
- smtpd_helo_restrictions:客户端发完EHLO/HELO后执行
- smtpd_sender_restrictions:客户端发完MAIL FROM后执行
- smtpd_recipient_restrictions/smtpd_relay_restrictions:客户端发完RCPT TO后执行
- SASL认证:客户端发AUTH命令时触发(在HELO之后,RCPT TO之前)
只要你把限制规则放在对应的阶段,再关掉延迟拒绝,就能精准把恶意请求拦在想要的节点。
备注:内容来源于stack exchange,提问作者Jonathan Wakely

