第 9 章:DMARC 策略与报告
第 9 章:DMARC 策略与报告
DMARC 是 SPF 和 DKIM 的指挥官——定义策略,收集报告,确保认证体系有效运作。
9.1 DMARC 概述
9.1.1 什么是 DMARC
DMARC(Domain-based Message Authentication, Reporting, and Conformance)是一种基于 SPF 和 DKIM 的邮件认证策略框架。它不仅验证邮件,还定义了验证失败时的处理策略,并提供报告机制。
DMARC 的三大功能:
| 功能 | 说明 |
|---|---|
| 认证(Authentication) | 基于 SPF 和 DKIM 验证邮件 |
| 策略(Policy) | 定义验证失败时的处理方式 |
| 报告(Reporting) | 接收验证结果的聚合报告和失败报告 |
9.1.2 DMARC 工作流程
发送方发送邮件
│
▼
接收方 MTA
│
├─► 1. SPF 检查
│ │
│ └─► SPF 对齐检查
│
├─► 2. DKIM 检查
│ │
│ └─► DKIM 对齐检查
│
├─► 3. 综合判断
│ SPF PASS + 对齐 → DMARC PASS
│ DKIM PASS + 对齐 → DMARC PASS
│ 都失败 → DMARC FAIL
│
├─► 4. 应用 DMARC 策略
│ p=none → 放行
│ p=quarantine → 隔离(垃圾邮件)
│ p=reject → 拒绝
│
└─► 5. 发送报告(可选)
聚合报告 → 发送到 rua 地址
失败报告 → 发送到 ruf 地址
9.1.3 DMARC 对齐(Alignment)
DMARC 对齐是 DMARC 的核心概念,要求 SPF/DKIM 验证的域名与邮件 From 头的域名匹配。
对齐检查示例:
From: [email protected]
MAIL FROM: [email protected] ← SPF 对齐 ✅
DKIM d=example.com ← DKIM 对齐 ✅
From: [email protected]
MAIL FROM: [email protected] ← SPF 对齐(子域匹配)⚠️
DKIM d=example.com ← DKIM 对齐 ✅
From: [email protected]
MAIL FROM: [email protected] ← SPF 对齐失败 ❌
DKIM d=other.com ← DKIM 对齐失败 ❌
对齐模式:
| 模式 | 说明 | 配置 |
|---|---|---|
| 严格(Strict) | 域名必须完全匹配 | adkim=s; aspf=s |
| 宽松(Relaxed) | 子域名也匹配 | adkim=r; aspf=r(默认) |
9.2 配置 DMARC 记录
9.2.1 DMARC TXT 记录格式
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
9.2.2 DMARC 标签说明
必需标签:
| 标签 | 说明 | 示例 |
|---|---|---|
v | DMARC 版本 | DMARC1 |
p | 策略 | none, quarantine, reject |
报告标签:
| 标签 | 说明 | 示例 |
|---|---|---|
rua | 聚合报告接收地址 | mailto:[email protected] |
ruf | 失败报告接收地址 | mailto:[email protected] |
可选标签:
| 标签 | 说明 | 默认值 | 示例 |
|---|---|---|---|
sp | 子域名策略 | 同 p | reject |
adkim | DKIM 对齐模式 | r(宽松) | s(严格) |
aspf | SPF 对齐模式 | r(宽松) | s(严格) |
ri | 报告间隔(秒) | 86400 | 3600 |
fo | 失败报告选项 | 0 | 1 |
pct | 策略应用百分比 | 100 | 50 |
rf | 失败报告格式 | afrf | iodef |
9.2.3 策略(Policy)详解
| 策略 | 含义 | 接收方行为 | 适用阶段 |
|---|---|---|---|
p=none | 不做处理 | 放行邮件 | 监控阶段 |
p=quarantine | 隔离 | 标记为垃圾邮件 | 过渡阶段 |
p=reject | 拒绝 | 不接收邮件 | 全面保护 |
9.2.4 失败报告选项(fo)
| 值 | 含义 |
|---|---|
0 | SPF 和 DKIM 都失败时生成报告 |
1 | 任一失败时生成报告 |
d | DKIM 验证失败时生成报告 |
s | SPF 验证失败时生成报告 |
9.3 DMARC 配置实践
9.3.1 渐进式配置方案
阶段 1:监控模式
; 仅监控,不采取行动
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; ri=3600"
阶段 2:隔离模式
; 隔离未验证的邮件
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1"
阶段 3:拒绝模式
; 拒绝未验证的邮件
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; ri=86400"
9.3.2 完整 DMARC 配置示例
; 生产环境完整配置
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject; adkim=s; aspf=s; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; ri=86400; pct=100"
配置解读:
| 标签 | 值 | 含义 |
|---|---|---|
p=reject | reject | 主域名:拒绝未验证邮件 |
sp=reject | reject | 子域名:拒绝未验证邮件 |
adkim=s | strict | DKIM 严格对齐 |
aspf=s | strict | SPF 严格对齐 |
rua | mailto:… | 聚合报告发送地址 |
ruf | mailto:… | 失败报告发送地址 |
fo=1 | 1 | 任一失败即生成报告 |
ri=86400 | 86400 | 报告间隔 24 小时 |
9.3.3 多域名 DMARC 配置
; example.com
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
; example.org
_dmarc.example.org. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
; 使用 redirect 重定向到统一报告地址
_dmarc.sub.example.com. IN TXT "v=DMARC1; redirect=example.com"
9.4 验证 DMARC 配置
9.4.1 命令行验证
# 查询 DMARC 记录
dig TXT _dmarc.example.com +short
# 使用 nslookup
nslookup -type=TXT _dmarc.example.com
# 使用 Python 验证
python3 -c "
import dns.resolver
answers = dns.resolver.resolve('_dmarc.example.com', 'TXT')
for rdata in answers:
print(rdata.to_text())
"
9.4.2 DMARC 验证脚本
#!/bin/bash
# dmarc-check.sh — DMARC 记录检查脚本
DOMAIN="$1"
if [ -z "$DOMAIN" ]; then
echo "用法: $0 <域名>"
exit 1
fi
echo "=== DMARC 记录检查: $DOMAIN ==="
# 1. 查询 DMARC 记录
echo "[1/5] 查询 DMARC TXT 记录..."
DMARC_RECORD=$(dig +short TXT _dmarc.$DOMAIN | tr -d '"')
if [ -z "$DMARC_RECORD" ]; then
echo " ❌ 未找到 DMARC 记录"
exit 1
else
echo " ✅ DMARC 记录: $DMARC_RECORD"
fi
# 2. 检查版本
echo "[2/5] 检查 DMARC 版本..."
if echo "$DMARC_RECORD" | grep -q "^v=DMARC1"; then
echo " ✅ DMARC 版本正确"
else
echo " ❌ DMARC 版本格式错误"
fi
# 3. 检查策略
echo "[3/5] 检查策略..."
if echo "$DMARC_RECORD" | grep -q "p=reject"; then
echo " ✅ 策略: reject(推荐)"
elif echo "$DMARC_RECORD" | grep -q "p=quarantine"; then
echo " ⚠️ 策略: quarantine(建议升级到 reject)"
elif echo "$DMARC_RECORD" | grep -q "p=none"; then
echo " ⚠️ 策略: none(仅监控,建议最终升级到 reject)"
fi
# 4. 检查报告地址
echo "[4/5] 检查报告地址..."
if echo "$DMARC_RECORD" | grep -q "rua=mailto:"; then
RUA=$(echo "$DMARC_RECORD" | grep -oP 'rua=mailto:\K[^;]+')
echo " ✅ 聚合报告地址: $RUA"
else
echo " ⚠️ 未配置聚合报告地址"
fi
if echo "$DMARC_RECORD" | grep -q "ruf=mailto:"; then
RUF=$(echo "$DMARC_RECORD" | grep -oP 'ruf=mailto:\K[^;]+')
echo " ✅ 失败报告地址: $RUF"
else
echo " ⚠️ 未配置失败报告地址"
fi
# 5. 检查对齐模式
echo "[5/5] 检查对齐模式..."
if echo "$DMARC_RECORD" | grep -q "adkim=s"; then
echo " DKIM 对齐: strict"
else
echo " DKIM 对齐: relaxed(默认)"
fi
if echo "$DMARC_RECORD" | grep -q "aspf=s"; then
echo " SPF 对齐: strict"
else
echo " SPF 对齐: relaxed(默认)"
fi
echo ""
echo "=== 检查完成 ==="
9.4.3 在线验证工具
| 工具 | 地址 | 功能 |
|---|---|---|
| MXToolbox | https://mxtoolbox.com/dmarc.aspx | DMARC 记录检查 |
| dmarcian | https://dmarcian.com/dmarc-inspector/ | DMARC 分析 |
| Google Admin Toolbox | https://toolbox.googleapps.com/apps/checkmx/ | 综合邮件检查 |
| DMARC Analyzer | https://dmarcanalyzer.com/ | 报告分析 |
9.5 DMARC 报告分析
9.5.1 聚合报告(Aggregate Reports)
聚合报告以 XML 格式发送,包含验证统计信息:
<?xml version="1.0" encoding="UTF-8"?>
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<email>[email protected]</email>
<report_id>1234567890</report_id>
<date_range>
<begin>1715385600</begin>
<end>1715472000</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>reject</p>
<sp>reject</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>203.0.113.10</source_ip>
<count>150</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>example.com</domain>
<result>pass</result>
<selector>mail</selector>
</dkim>
<spf>
<domain>example.com</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>
9.5.2 报告解析工具
# 安装解析工具
pip install dmarc-report-analyzer
# 使用脚本解析
#!/bin/bash
# parse-dmarc-reports.sh — DMARC 报告解析脚本
REPORT_DIR="/var/mail/dmarc-reports"
PARSED_DIR="/var/mail/dmarc-parsed"
mkdir -p "$PARSED_DIR"
# 解压报告
for report in $REPORT_DIR/*.gz; do
echo "解析: $report"
gunzip -c "$report" | python3 -c "
import sys
import xml.etree.ElementTree as ET
xml_data = sys.stdin.read()
root = ET.fromstring(xml_data)
org = root.find('.//report_metadata/org_name').text
domain = root.find('.//policy_published/domain').text
print(f'组织: {org}')
print(f'域名: {domain}')
for record in root.findall('.//record'):
ip = record.find('.//source_ip').text
count = record.find('.//count').text
dkim = record.find('.//policy_evaluated/dkim').text
spf = record.find('.//policy_evaluated/spf').text
print(f' IP: {ip}, 数量: {count}, DKIM: {dkim}, SPF: {spf}')
"
done
9.5.3 报告分析服务
| 服务 | 免费/付费 | 功能 |
|---|---|---|
| dmarcian | 免费/付费 | 专业报告分析 |
| DMARC Analyzer | 付费 | 企业级分析 |
| Postmark DMARC | 免费 | 基础报告查看 |
| Google Postmaster | 免费 | Gmail 投递分析 |
9.6 配置报告接收
9.6.1 创建报告接收邮箱
# 创建专用邮箱
sudo postconf -e "virtual_alias_maps = hash:/etc/postfix/virtual"
# 添加别名
# /etc/postfix/virtual
[email protected] [email protected]
[email protected] [email protected]
sudo postmap /etc/postfix/virtual
sudo systemctl reload postfix
9.6.2 使用外部报告服务
; 使用 dmarcian 的报告收集服务
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
9.6.3 自动化报告处理
#!/bin/bash
# dmarc-report-processor.sh — 自动处理 DMARC 报告
REPORT_EMAIL="/var/mail/vhosts/example.com/dmarc-rua/new/*"
OUTPUT_DIR="/var/www/dmarc-reports/$(date +%Y-%m-%d)"
mkdir -p "$OUTPUT_DIR"
# 处理新报告
for email in $REPORT_EMAIL; do
echo "处理: $email"
# 提取附件
munpack -q -C "$OUTPUT_DIR" "$email"
# 解压 .gz 文件
for gz in "$OUTPUT_DIR"/*.gz; do
[ -f "$gz" ] && gunzip "$gz"
done
# 移动已处理的邮件
mv "$email" /var/mail/vhosts/example.com/dmarc-rua/cur/
done
# 解析报告
for xml in "$OUTPUT_DIR"/*.xml; do
[ -f "$xml" ] && python3 /usr/local/bin/parse-dmarc-xml.py "$xml" >> "$OUTPUT_DIR/report-summary.txt"
done
echo "报告处理完成: $OUTPUT_DIR"
9.7 业务场景:企业 DMARC 部署
场景描述
一家电子商务企业需要部署 DMARC,要求:
- 保护品牌不被冒用
- 了解所有使用域名发送邮件的来源
- 逐步从监控模式升级到拒绝模式
部署计划
| 阶段 | 策略 | 持续时间 | 目标 |
|---|---|---|---|
| 第 1 周 | p=none | 7 天 | 收集数据,识别合法来源 |
| 第 2-3 周 | p=none | 14 天 | 验证配置,修复问题 |
| 第 4 周 | p=quarantine; pct=25 | 7 天 | 测试隔离策略 |
| 第 5 周 | p=quarantine; pct=100 | 7 天 | 全面隔离 |
| 第 6 周+ | p=reject | 持续 | 全面保护 |
配置示例
# 第 1 周:监控模式
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; fo=1; ri=3600"
# 第 4 周:隔离模式(25%)
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1"
# 第 6 周:拒绝模式
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1"
9.8 注意事项
⚠️ 报告邮箱配置:
rua和ruf的邮箱地址必须能够接收邮件- 如果报告地址是外部域名,需要在外部域名添加 DMARC 记录授权:
example.com._report._dmarc.external.com IN TXT "v=DMARC1"
- 聚合报告可能很大,确保邮箱有足够空间
⚠️ 渐进式部署:
- 不要直接设置
p=reject,否则合法邮件可能被误拒- 先使用
p=none收集数据至少 2-4 周- 分析报告,修复所有 SPF/DKIM 问题后再升级策略
💡 DMARC 与第三方服务:
- 使用第三方服务发送邮件时,确保它们支持 SPF 和 DKIM
- 如果第三方服务使用自己的域名(如
@service.com),则 DMARC 检查的是service.com而非你的域名- 要求第三方服务使用你的域名发送,并配置 DKIM 签名