强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 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 标签说明

必需标签

标签说明示例
vDMARC 版本DMARC1
p策略none, quarantine, reject

报告标签

标签说明示例
rua聚合报告接收地址mailto:[email protected]
ruf失败报告接收地址mailto:[email protected]

可选标签

标签说明默认值示例
sp子域名策略preject
adkimDKIM 对齐模式r(宽松)s(严格)
aspfSPF 对齐模式r(宽松)s(严格)
ri报告间隔(秒)864003600
fo失败报告选项01
pct策略应用百分比10050
rf失败报告格式afrfiodef

9.2.3 策略(Policy)详解

策略含义接收方行为适用阶段
p=none不做处理放行邮件监控阶段
p=quarantine隔离标记为垃圾邮件过渡阶段
p=reject拒绝不接收邮件全面保护

9.2.4 失败报告选项(fo)

含义
0SPF 和 DKIM 都失败时生成报告
1任一失败时生成报告
dDKIM 验证失败时生成报告
sSPF 验证失败时生成报告

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=rejectreject主域名:拒绝未验证邮件
sp=rejectreject子域名:拒绝未验证邮件
adkim=sstrictDKIM 严格对齐
aspf=sstrictSPF 严格对齐
ruamailto:…聚合报告发送地址
rufmailto:…失败报告发送地址
fo=11任一失败即生成报告
ri=8640086400报告间隔 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 在线验证工具

工具地址功能
MXToolboxhttps://mxtoolbox.com/dmarc.aspxDMARC 记录检查
dmarcianhttps://dmarcian.com/dmarc-inspector/DMARC 分析
Google Admin Toolboxhttps://toolbox.googleapps.com/apps/checkmx/综合邮件检查
DMARC Analyzerhttps://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=none7 天收集数据,识别合法来源
第 2-3 周p=none14 天验证配置,修复问题
第 4 周p=quarantine; pct=257 天测试隔离策略
第 5 周p=quarantine; pct=1007 天全面隔离
第 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 注意事项

⚠️ 报告邮箱配置

  • ruaruf 的邮箱地址必须能够接收邮件
  • 如果报告地址是外部域名,需要在外部域名添加 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 签名

9.9 扩展阅读


上一章← 第 8 章:SPF 发件人策略框架 下一章第 10 章:Webmail 与邮件客户端集成 →