Skip to main content

Appendix G. Local Policy Considerations (本地策略考虑)

Appendix G. Local Policy Considerations (本地策略考虑)

本附录讨论接收方在实施 SPF 时应考虑的本地策略。

G.1 Policy for SPF Pass (SPF Pass 的策略)

G.1.1 基本处理

SPF Pass 结果: 发件人已通过 SPF 验证

建议操作:

1. 接受邮件
2. 继续其他反垃圾邮件检查
3. 不应仅基于 SPF pass 就完全信任

原因:

  • SPF 仅验证 SMTP 发件人
  • 不验证消息内容
  • 不验证 From: 标头
  • 攻击者可以从授权服务器发送垃圾邮件

G.1.2 评分系统

SpamAssassin 示例:

# SPF pass 降低垃圾邮件分数
score SPF_PASS -0.001

# 但不足以完全信任
# 仍需要其他检查: 内容分析, DKIM, DMARC 等

rspamd 示例:

-- SPF pass 给予正面权重
spf {
symbol_pass = "R_SPF_ALLOW";
symbol_fail = "R_SPF_FAIL";
symbol_softfail = "R_SPF_SOFTFAIL";
symbol_neutral = "R_SPF_NEUTRAL";

-- 权重
score = {
R_SPF_ALLOW = -0.2,
R_SPF_FAIL = 6.0,
R_SPF_SOFTFAIL = 3.0,
R_SPF_NEUTRAL = 0.0
}
}

G.1.3 白名单考虑

已知良好发件人:

# 对于已知可信域的 SPF pass, 可以降低其他检查的严格度
if spf_pass and sender_domain in trusted_domains:
reduce_spam_score()
skip_greylisting()

示例实现:

TRUSTED_DOMAINS = [
'example.com',
'partner.org',
'bank.com'
]

def apply_whitelist_policy(spf_result, sender_domain):
if spf_result == 'pass' and sender_domain in TRUSTED_DOMAINS:
return 'WHITELIST'
return 'CONTINUE_CHECKS'

G.2 Policy for SPF Fail (SPF Fail 的策略)

G.2.1 严格策略

立即拒绝:

# Postfix 配置
smtpd_recipient_restrictions =
reject_unauth_destination,
check_policy_service unix:private/spf-policy,
permit

# SPF 策略服务
if spf_result == 'fail':
return 'REJECT SPF validation failed'

SMTP 响应示例:

550 5.7.1 SPF validation failed for [email protected]
550 5.7.1 Please see http://www.openspf.org/Why?s=mfrom&id=sender%40example.com&ip=192.0.2.1

优点:

  • 有效阻止伪造邮件
  • 减少垃圾邮件

缺点:

  • 可能阻止合法的转发邮件
  • 可能阻止邮件列表邮件
  • 配置错误的 SPF 记录导致误报

G.2.2 宽松策略

增加垃圾邮件分数:

# SpamAssassin
score SPF_FAIL 5.0
score SPF_SOFTFAIL 3.0

# 不自动拒绝, 而是增加分数
# 结合其他因素决定

实现示例:

def calculate_spam_score(message):
score = 0

# SPF 检查
if message.spf_result == 'fail':
score += 5.0
elif message.spf_result == 'softfail':
score += 3.0
elif message.spf_result == 'pass':
score -= 0.2

# 其他检查...
if message.dkim_result == 'pass':
score -= 0.5

# 内容分析
score += content_analysis(message)

# 决策
if score > 10:
return 'REJECT'
elif score > 5:
return 'QUARANTINE'
else:
return 'ACCEPT'

G.2.3 渐进式策略

阶段 1: 监控模式(0-30天)

# 记录但不采取行动
if spf_result == 'fail':
log_spf_failure(sender, recipient, ip)
add_header('X-SPF-Status', 'fail')
# 但仍然接受邮件

阶段 2: 标记模式(31-90天)

# 标记并隔离
if spf_result == 'fail':
move_to_spam_folder()
add_header('X-SPF-Warning', 'This message failed SPF validation')

阶段 3: 拒绝模式(90天后)

# 拒绝明显的伪造
if spf_result == 'fail' and not is_exception(sender):
reject('SPF validation failed')

G.2.4 例外列表

场景: 已知会导致 SPF fail 的合法来源

EXCEPTIONS = {
# 邮件列表
'List-Id': [
'important-list.mailinglist.org',
'company-announce.lists.example.com'
],

# 转发服务
'forward_domains': [
'forward.alumni.university.edu'
],

# 特定发件人
'sender_whitelist': [
'[email protected]'
]
}

def should_apply_spf_fail_policy(message):
# 检查是否为邮件列表
list_id = message.get_header('List-Id')
if list_id and list_id in EXCEPTIONS['List-Id']:
return False

# 检查发件人白名单
sender = message.get_sender()
if sender in EXCEPTIONS['sender_whitelist']:
return False

return True

G.3 Policy for SPF Permerror (SPF Permerror 的策略)

G.3.1 处理方式

Permerror 含义: SPF 记录存在永久性错误

可能原因:

- 语法错误
- 多个 SPF 记录
- DNS 查询限制超标
- 无效的机制或修饰符

建议策略:

if spf_result == 'permerror':
# 记录错误
log_spf_permerror(sender_domain, error_details)

# 通知管理员(可选)
notify_admin(sender_domain, error_details)

# 策略选项:
# 选项 1: 视为无 SPF(宽松)
treat_as_none()

# 选项 2: 增加垃圾邮件分数(推荐)
add_spam_score(2.0)

# 选项 3: 拒绝(严格, 不推荐)
# reject('Sender has invalid SPF configuration')

G.3.2 通知机制

通知发送域管理员:

def notify_sender_domain(domain, error):
# 尝试查找 postmaster 地址
postmaster = f"postmaster@{domain}"

# 发送通知(限制频率, 避免骚扰)
if not recently_notified(domain):
send_notification(
to=postmaster,
subject=f"SPF configuration error for {domain}",
body=f"""
Your domain's SPF record has an error:
{error}

Please correct this issue to improve email deliverability.
"""
)
mark_as_notified(domain)

G.4 Policy for SPF Temperror (SPF Temperror 的策略)

G.4.1 处理方式

Temperror 含义: 临时性 DNS 错误

建议策略:

if spf_result == 'temperror':
# 选项 1: 临时拒绝(推荐)
return '4xx Temporary DNS error, please try again later'

# 选项 2: 接受但标记
add_header('X-SPF-Temperror', 'true')
log_temperror(sender, recipient)
accept_message()

SMTP 响应:

450 4.7.1 SPF temporary error during validation, please retry

优点: 发件人 MTA 会稍后重试

G.4.2 重试逻辑

Postfix 配置:

# main.cf
# 临时失败时的重试延迟
queue_run_delay = 300s
minimal_backoff_time = 300s
maximal_backoff_time = 4000s

监控 Temperror:

# 如果 temperror 率过高, 可能是 DNS 问题
def monitor_temperror_rate():
rate = get_temperror_rate()
if rate > 0.05: # 5%
alert("High SPF temperror rate detected: DNS issues?")

G.5 Policy for SPF Softfail (SPF Softfail 的策略)

G.5.1 处理建议

Softfail 含义: 主机可能未授权(~all)

推荐策略:

- 接受邮件
- 标记为可疑
- 增加适度的垃圾邮件分数
- 可选: 放入垃圾邮件文件夹

实现:

if spf_result == 'softfail':
# 增加垃圾邮件分数(比 fail 低)
spam_score += 2.0

# 添加标头
add_header('X-SPF-Status', 'softfail')

# 如果总分数超过阈值, 隔离
if spam_score > 5.0:
move_to_spam_folder()
else:
deliver_to_inbox()

G.6 Policy for SPF Neutral and None (SPF Neutral 和 None 的策略)

G.6.1 Neutral (?all)

含义: 发件人明确表示不断言

策略:

if spf_result == 'neutral':
# 视为无 SPF
# 不增加或减少垃圾邮件分数
# 继续其他检查
pass

G.6.2 None (无 SPF 记录)

含义: 域没有发布 SPF 记录

策略选项:

选项 1: 宽松(推荐)

if spf_result == 'none':
# 不惩罚无 SPF 的域
# 许多合法域仍未部署 SPF
continue_normal_checks()

选项 2: 轻微惩罚

if spf_result == 'none':
# 轻微增加分数(鼓励 SPF 部署)
spam_score += 0.5

G.7 Combined Authentication Policies (综合认证策略)

G.7.1 SPF + DKIM

决策矩阵:

SPFDKIM操作
passpass接受(低垃圾邮件分数)
passfail接受(正常检查)
failpass接受(DKIM 更可靠)
failfail增加分数或拒绝

实现:

def evaluate_authentication(spf, dkim):
if spf == 'pass' and dkim == 'pass':
return -1.0 # 降低垃圾邮件分数
elif spf == 'pass' or dkim == 'pass':
return 0.0 # 中性
elif spf == 'fail' and dkim == 'fail':
return 8.0 # 高度可疑
else:
return 2.0 # 轻微可疑

G.7.2 SPF + DKIM + DMARC

DMARC 对齐检查:

def check_dmarc_alignment(message):
# DMARC 要求 SPF 或 DKIM 与 From: 域对齐
from_domain = extract_domain(message.get_header('From'))

# SPF 对齐
spf_aligned = (message.spf_result == 'pass' and
message.mail_from_domain == from_domain)

# DKIM 对齐
dkim_aligned = (message.dkim_result == 'pass' and
message.dkim_domain == from_domain)

# DMARC 通过需要至少一个对齐
dmarc_pass = spf_aligned or dkim_aligned

return dmarc_pass

策略应用:

def apply_dmarc_policy(message):
dmarc_policy = lookup_dmarc_policy(message.from_domain)

if not dmarc_policy:
# 无 DMARC 策略
return apply_local_policy(message)

dmarc_pass = check_dmarc_alignment(message)

if dmarc_pass:
return 'ACCEPT'

# DMARC 失败, 应用发布的策略
if dmarc_policy.p == 'reject':
return 'REJECT'
elif dmarc_policy.p == 'quarantine':
return 'QUARANTINE'
else: # none
return apply_local_policy(message)

G.8 User-Level Policies (用户级策略)

G.8.1 用户可配置选项

白名单:

用户可以添加信任的发件人:
- 即使 SPF fail 也接受
- 绕过垃圾邮件检查

黑名单:

用户可以阻止特定发件人:
- 即使 SPF pass 也拒绝

严格程度:

用户可以选择:
- 宽松: 接受所有邮件, 仅标记可疑
- 正常: 平衡安全和可用性
- 严格: 积极过滤, 可能误报

G.8.2 实现示例

class UserPolicy:
def __init__(self, user_id):
self.user_id = user_id
self.whitelist = load_whitelist(user_id)
self.blacklist = load_blacklist(user_id)
self.strictness = load_strictness(user_id)

def evaluate(self, message):
sender = message.get_sender()

# 检查黑名单
if sender in self.blacklist:
return 'REJECT'

# 检查白名单
if sender in self.whitelist:
return 'ACCEPT'

# 应用基于严格程度的策略
if self.strictness == 'strict':
return self._strict_policy(message)
elif self.strictness == 'normal':
return self._normal_policy(message)
else: # loose
return self._loose_policy(message)

def _strict_policy(self, message):
if message.spf_result == 'fail':
return 'REJECT'
elif message.spam_score > 5.0:
return 'REJECT'
return 'ACCEPT'

def _normal_policy(self, message):
if message.spam_score > 10.0:
return 'REJECT'
elif message.spam_score > 5.0:
return 'QUARANTINE'
return 'ACCEPT'

def _loose_policy(self, message):
if message.spam_score > 15.0:
return 'QUARANTINE'
return 'ACCEPT'

G.9 Reporting and Feedback (报告和反馈)

G.9.1 DMARC 报告

生成聚合报告:

def generate_dmarc_report(domain, period_start, period_end):
"""
生成 DMARC 聚合报告 (RUA)
"""
records = get_dmarc_records(domain, period_start, period_end)

report = {
'report_metadata': {
'org_name': 'Your Organization',
'email': '[email protected]',
'report_id': generate_report_id(),
'date_range': {
'begin': period_start,
'end': period_end
}
},
'policy_published': lookup_dmarc_policy(domain),
'records': []
}

# 按 IP 聚合
for ip, data in aggregate_by_ip(records):
report['records'].append({
'source_ip': ip,
'count': data['count'],
'policy_evaluated': {
'disposition': data['disposition'],
'dkim': data['dkim_result'],
'spf': data['spf_result']
}
})

return report

G.9.2 反馈循环

处理用户反馈:

def handle_user_feedback(message_id, feedback_type):
"""
处理用户反馈 (报告垃圾邮件/非垃圾邮件)
"""
message = retrieve_message(message_id)

if feedback_type == 'spam':
# 用户报告为垃圾邮件
update_reputation(message.sender, -1.0)

# 如果是 SPF pass 但被报告为垃圾邮件
if message.spf_result == 'pass':
log_false_positive(message.sender_domain)

elif feedback_type == 'not_spam':
# 用户报告误判
update_reputation(message.sender, +1.0)

# 如果是 SPF fail 但是合法邮件
if message.spf_result == 'fail':
consider_exception(message.sender)

G.10 Best Practices Summary (最佳实践摘要)

G.10.1 推荐策略

1. 结合多种认证方法(SPF + DKIM + DMARC)
2. 不要仅依赖 SPF 做决策
3. 使用渐进式部署(监控 → 标记 → 拒绝)
4. 维护例外列表(邮件列表、已知转发等)
5. 提供用户可配置选项
6. 实施报告和反馈机制
7. 定期审查和调整策略
8. 监控误报率
9. 保持策略文档更新
10. 与发件人社区沟通

G.10.2 避免的陷阱

❌ 仅基于 SPF fail 就拒绝所有邮件
❌ 忽略 DKIM 结果
❌ 没有例外机制
❌ 不监控误报
❌ 策略过于严格导致合法邮件丢失
❌ 策略过于宽松失去防护作用
❌ 不提供用户反馈渠道
❌ 不生成 DMARC 报告

G.10.3 持续改进

1. 定期审查日志和报告
2. 分析误报和漏报
3. 调整评分权重
4. 更新白名单/黑名单
5. 跟踪行业最佳实践
6. 测试新的过滤技术
7. 收集用户反馈
8. 与发件人合作改进