Appendix F. MTA Relays (MTA 中继)
Appendix F. MTA Relays (MTA 中继)
本附录讨论 MTA 中继场景下的 SPF 实施。
F.1 Relay Types (中继类型)
F.1.1 开放中继(不推荐)
定义: 允许任何人使用的邮件中继
SPF 问题:
- 开放中继是垃圾邮件的主要来源
- 无法验证原始发件人
- SPF 记录无法覆盖所有可能的发件人
建议: 不要运行开放中继
F.1.2 认证中继
定义: 要求 SMTP AUTH 的中继
配置:
# Postfix 配置
smtpd_sasl_auth_enable = yes
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
SPF 配置:
company.com IN TXT "v=spf1 mx ip4:203.0.113.50 -all"
其中 203.0.113.50 是认证中继的 IP。
F.1.3 内部中继
场景: 组织内部的邮件路由
[用户] → [内部中继] → [边界 MTA] → [互联网]
SPF 考虑:
- 仅边界 MTA 的 IP 需要在 SPF 中
- 内部中继不需要 SPF 授权(不直接连接外部)
配置示例:
# 仅边界 MTA
company.com IN TXT "v=spf1 ip4:203.0.113.0/28 -all"
# 203.0.113.0/28 是边界 MTA 的 IP 范围
F.2 SPF with Authenticated Relay (SPF 与认证中继)
F.2.1 标准配置
场景: 用户通过认证中继发送邮件
[用户设备] --[SMTP AUTH]--> [中继] --> [接收方]
MAIL FROM: [email protected]
实际 IP: 中继服务器的 IP
SPF 记录:
company.com IN TXT "v=spf1 ip4:RELAY_IP -all"
Postfix 配置(中继服务器):
# main.cf
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
# 要求认证才能中继
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
# 添加 Received-SPF 标头
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
F.2.2 动态 IP 用户
问题: 用户从动态 IP 地址(家庭、咖啡店等)连接
解决方案: 不在 SPF 中列出用户 IP, 仅列出中继 IP
错误配置(不可行):
company.com IN TXT "v=spf1 ip4:ALL_POSSIBLE_USER_IPS -all"
正确配置:
company.com IN TXT "v=spf1 ip4:RELAY_SERVER_IP -all"
用户配置(邮件客户端):
SMTP 服务器: smtp.company.com
端口: 587 (Submission)
安全: STARTTLS
认证: 用户名/密码
F.3 Submission Servers (提交服务器)
F.3.1 端口 587(推荐)
RFC 6409 定义了邮件提交端口 587
特点:
- 专用于邮件提交(非中继)
- 要求认证
- 强制 STARTTLS
- 与端口 25 分离
Postfix 配置:
# master.cf
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
SPF 配置:
# 提交服务器的 IP
company.com IN TXT "v=spf1 ip4:203.0.113.100 -all"
F.3.2 端口 465(SMTPS)
历史: 原 SMTPS 端口, 现已标准化
特点:
- 隐式 TLS(立即启动 TLS)
- 与 STARTTLS 不同
- 某些邮件客户端首选
配置:
# master.cf
smtps inet n - n - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
F.4 Multi-Tier Architecture (多层架构)
F.4.1 架构示例
层级 1: 用户设备
↓ (SMTP AUTH)
层级 2: 提交服务器(内部)
↓ (内部转发)
层级 3: 内容过滤/病毒扫描
↓ (内部转发)
层级 4: 边界 MTA(出站)
↓ (互联网)
目标: 接收方
SPF 配置:
# 仅需要授权层级 4 的 IP
company.com IN TXT "v=spf1 ip4:BORDER_MTA_IPS -all"
F.4.2 内部信任
配置示例(Postfix):
层级 2(提交服务器):
# main.cf
mynetworks = 10.0.0.0/8 # 信任内部网络
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject
层级 3(内容过滤):
# main.cf
mynetworks = 10.0.1.0/24 # 信任提交服务器
content_filter = smtp-amavis:[127.0.0.1]:10024
层级 4(边界 MTA):
# main.cf
mynetworks = 10.0.2.0/24 # 信任内容过滤器
smtpd_relay_restrictions = permit_mynetworks, reject
F.5 Header Rewriting (标头重写)
F.5.1 保留原始信息
问题: 多层中继可能丢失原始发件人信息
解决方案: 添加自定义标头
Postfix 配置:
# header_checks
/^Received:/ PREPEND X-Original-IP: ${client_address}
/^From:/ PREPEND X-Original-From: $1
结果:
X-Original-IP: 192.168.1.100
X-Original-From: [email protected]
Received: from client ([203.0.113.50])
F.5.2 SRS(Sender Rewriting Scheme)
用于: 转发场景
配置 (PostSRSd):
# 安装 postsrsd
apt-get install postsrsd
# Postfix 配置
sender_canonical_maps = tcp:localhost:10001
recipient_canonical_maps = tcp:localhost:10002
重写示例:
F.6 Relay Authentication Methods (中继认证方法)
F.6.1 SMTP AUTH
机制:
- PLAIN(明文, 需要 TLS)
- LOGIN(类似 PLAIN)
- CRAM-MD5(挑战响应)
- DIGEST-MD5(更安全)
Postfix + Dovecot SASL:
# main.cf
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
# Dovecot 配置
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
F.6.2 IP 白名单
场景: 信任特定 IP 范围
# main.cf
mynetworks =
10.0.0.0/8,
203.0.113.0/24
smtpd_relay_restrictions = permit_mynetworks, reject
SPF 配置:
# 包含所有出站 IP
company.com IN TXT "v=spf1 ip4:203.0.113.0/24 -all"
F.6.3 TLS 客户端证书
高安全场景:
# main.cf
smtpd_tls_ask_ccert = yes
smtpd_tls_req_ccert = yes
smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
# 基于证书允许中继
smtpd_relay_restrictions =
permit_tls_clientcerts,
reject
F.7 Relay Logging and Monitoring (中继日志和监控)
F.7.1 日志记录
启用详细日志(Postfix):
# main.cf
smtpd_tls_loglevel = 1
smtp_tls_loglevel = 1
# 记录 SASL 认证
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
日志示例:
postfix/submission/smtpd[12345]: connect from client[192.168.1.100]
postfix/submission/smtpd[12345]: SASL LOGIN authentication succeeded: [email protected]
postfix/submission/smtpd[12345]: client=client[192.168.1.100], sasl_method=LOGIN, [email protected]
F.7.2 监控指标
关键指标:
- 认证成功/失败率
- 每用户发送量
- 每 IP 连接数
- 平均队列时间
- 退信率
- 垃圾邮件检测率
监控脚本:
# 统计认证失败
grep "authentication failed" /var/log/mail.log | wc -l
# 统计认证成功
grep "authentication succeeded" /var/log/mail.log | wc -l
# 按用户统计
grep "sasl_username=" /var/log/mail.log | \
cut -d= -f2 | cut -d, -f1 | sort | uniq -c | sort -rn
F.7.3 异常检测
检测暴力破解:
# fail2ban jail.conf
[postfix-sasl]
enabled = true
filter = postfix-sasl
port = smtp,submission,smtps
logpath = /var/log/mail.log
maxretry = 5
findtime = 600
bantime = 3600
检测异常发送:
# 监控脚本
def detect_anomaly(user, send_count):
# 获取用户的历史平均值
avg = get_user_average(user)
# 如果超过平均值 10 倍
if send_count > avg * 10:
alert(f"User {user} sending anomalously: {send_count} vs avg {avg}")
F.8 Best Practices (最佳实践)
F.8.1 中继安全
检查清单:
□ 禁用开放中继
□ 要求 SMTP AUTH
□ 强制使用 TLS
□ 实施速率限制
□ 监控认证失败
□ 定期审查日志
□ 实施 fail2ban 或类似工具
□ 使用强密码策略
F.8.2 SPF 配置
推荐:
1. 仅授权边界 MTA 的 IP
2. 使用 -all(严格模式)
3. 定期审查授权 IP
4. 监控 SPF 检查结果
5. 配合 DKIM 使用
6. 发布 DMARC 策略
F.8.3 故障排除
常见问题:
问题 1: 用户报告无法发送
检查:
- SMTP AUTH 配置正确
- 用户凭据有效
- 端口未被防火墙阻止
- TLS 证书有效
问题 2: 邮件被接收方拒绝
检查:
- 中继 IP 在 SPF 记录中
- DKIM 签名正确
- 反向 DNS 配置
- IP 不在黑名单中
问题 3: 性能问题
检查:
- 队列大小
- 并发连接数
- DNS 解析时间
- 磁盘 I/O
调试命令:
# 测试 SMTP AUTH
swaks --to [email protected] \
--from [email protected] \
--server smtp.company.com:587 \
--tls \
--auth LOGIN \
--auth-user [email protected] \
--auth-password PASSWORD
# 检查队列
mailq
postqueue -p
# 刷新队列
postqueue -f
# 查看实时日志
tail -f /var/log/mail.log