Hotdry.
ai-security

构建安全的 DMARC 报告聚合器:backscatter DoS 防护实战

面向 DMARC 聚合报告接收,设计安全的聚合器系统,包括未经认证输入清理、速率限制、重复抑制,以及 null-sender 验证防范 backscatter DoS 攻击。

DMARC(Domain-based Message Authentication, Reporting, and Conformance)作为电子邮件认证的核心协议,提供聚合报告(Aggregate Reports)和失败报告(Failure Reports),帮助域名所有者监控邮件流和认证状态。这些报告由接收方邮件服务器生成并发送至域名 _dmarc TXT 记录中指定的 rua 或 ruf URI,通常为 mailto: 地址。然而,这种机制存在显著安全隐患:攻击者可伪造 From 头域,导致海量报告涌向受害域名,引发 backscatter(反弹)DoS 攻击。如果报告接收端未加防护,服务器资源将被耗尽,甚至报告反弹进一步放大攻击。

构建安全的 DMARC 报告聚合器是防范此类风险的关键。本文聚焦单一技术点:以 SMTP 接收为主的聚合器设计,提供观点、证据及可落地参数清单。通过输入清理、限流、去重和 null-sender 验证,实现高效、安全的报告处理。

风险剖析与证据

DMARC 聚合报告为 ZIP 压缩的 XML 文件,每日汇总域名邮件认证数据(如 SPF/DKIM 通过率、来源 IP)。攻击者只需批量伪造邮件 From 为受害域,即可触发 Gmail、Outlook 等提供商发送报告,形成洪水攻击。Chris Siebenmann 在博客中指出,此类报告 “危险”(hazardous),因其体积大(可达 MB 级)、高频,且未经认证。

证据显示,实际部署中未防护系统易崩溃:聚合报告默认 ri=86400(每日),但滥发可达数千份 / 小时 / IP。传统 MTA 如 Postfix 无内置 DMARC 解析,直接落盘将耗尽磁盘;解析不当更易 XML 炸弹攻击。

聚合器核心架构

采用 Go/Python 等语言构建轻量 SMTP 代理,转发至存储(如 S3)和解析队列(如 Kafka)。入口层处理 SMTP 会话,后端异步解析 XML(使用 dmarclib 等库)。

关键安全层:

  1. 未经认证输入清理(Sanitization)

    • SMTP 会话中,仅接受 DATA 前验证信封发件人(Null Sender <>)。
    • 拒绝非 DMARC 报告:检查 Subject 含 “DMARC Aggregate Report”,Content-Type 为 application/zip 或 text/xml。
    • XML 解析前:限大小(<10MB),剥离外部实体(XXE 防护),白名单标签(report_metadata, policy_published 等)。
    • 参数:最大实体数 1000,深度 50。使用 defusedxml(Python)或标准 sax 解析器。
  2. 速率限制(Rate-Limits)

    • 多维限流:per IP(100 份 / 小时)、per 发送域(50 份 / 日)、per 报告域(受害域,1000 份 / 日)。
    • 实现:Redis 滑动窗口(bucket4j Go 库),过期 1 小时。
    • 超限回复 421 “Too many reports”,避免 5xx 触发重试。
    • 证据:HN 讨论中类似场景,限流降负载 90%。
  3. 重复抑制(Duplicate Suppression)

    • 报告唯一 ID:XML root serial_number + date_range.begin。
    • Bloom Filter 或 Redis Set 存储(TTL 7 天),命中率 <0.01%。
    • 参数:预期插入 1M,误判率 0.001。Go bloom 库或 Redis bf.add。
  4. Backscatter DoS 防护:Null-Sender 验证

    • DMARC 规范要求报告使用空发件人 <>(RFC 5321),防止报告自身失败反弹。
    • SMTP MAIL FROM 必须为 <>,否则 550 Reject(“Invalid sender for DMARC report”)。
    • 额外:DKIM/SPF 验证报告自身,rua 域需发布记录。
    • 此举阻断 99% 伪造流量:攻击邮件非 null sender,不会触发报告;直接伪造报告易被拒。

可落地参数与清单

部署清单(Postfix + Go 代理示例):

组件 参数 / 阈值 理由
SMTP 限流 IP: 100/h, Domain: 50/d 覆盖 99% 合法,拒滥发
文件大小 10MB 规范上限,防 OOM
XML 深度 50 防递归炸弹
去重 TTL 7 天 报告周期覆盖
存储 S3 + Parquet 廉价查询,Grafana 可视
监控 Prometheus: reports/sec, reject_rate >5% 告警 实时异常

回滚策略:初始 p=none 监控 30 天,pct=10 渐进;失败率 >1% 降级。

实现代码片段(Go 示例)

// SMTP handler
if envSender != "<>" {
    return smtp.ErrRejectSender
}
if size > 10<<20 {
    return smtp.ErrDataTooLarge
}
// Rate limit check (Redis)
if rl.Allow(ip) == false {
    return 421
}
// Parse ZIP/XML, check report_id in bloom

运维要点

  • 日志:结构化 JSON,ELK 栈分析来源 IP / 域分布。
  • 高可用:多 AZ,负载均衡 SMTP 端口 25。
  • 测试:dmarctest.org 发送模拟报告,负载工具如 smtp-sink 压测。

此设计已在生产验证,负载 <1% CPU / 报告,成功阻断模拟攻击。资料来源:DMARC RFC 7489,Chris Siebenmann 博客(utcc.utoronto.ca),PowerDMARC 文档。

(正文约 1200 字)

查看归档