我收到Google 的 DMARC 报告每天以包含 XML 文件的 zip 文件形式下载。我手动下载每个 zip 文件~/Documents/DMARC
。
我想汇总所有已保存的 DMARC 报告中的信息并生成一份人性化可读的报告(例如 LibreOffice Calc 电子表格中的表格)。我宁愿不要一直运行占用大量内存或 CPU 的服务。
关于如何做到这一点有什么建议吗?
背景信息
基于域的消息认证、报告和一致性 (DMARC) 是一种不断发展的技术标准DMARC 报告格式由该标准指定。它也看起来像 Ubuntu原生支持 DMARC,但我需要详细的说明。
上面的 Google 链接显示了输入 DMARC XML 文件格式和输出表格形式的示例。根据要求,它们粘贴在此处。
示例输入 XML 文件:
<?xml version="1.0" encoding="UTF-8" ?>
<feedback>
<report_metadata>
<org_name>solarmora.com</org_name>
<email>[email protected]</email>
<extra_contact_info>http://solarmora.com/dmarc/support</extra_contact_info>
<report_id>9391651994964116463</report_id>
<date_range>
<begin>1335571200</begin>
<end>1335657599</end>
</date_range>
</report_metadata>
<policy_published>
<domain>bix-business.com</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>203.0.113.209</source_ip>
<count>2</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>bix-business.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>bix-business.com</domain>
<result>fail</result>
<human_result></human_result>
</dkim>
<spf>
<domain>bix-business.com</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>
答案1
这些是我在 Ubuntu 22.04 上使用的步骤。我希望它们可以得到改进,以用于更广泛的用途,所以请发表评论并告诉我,我会尽力调整解决方案。
该解决方案将使用dmarcts-report-parser 包和mysql 服务器来自 Ubuntu 默认存储库。最终输出是一个 csv 文件,因此此解决方案可能最适合轻度用户(例如一个或两个域)和偶尔使用 DMARC 聚合报告的用户。
以下是 LibreOffice Calc 中输出 CSV 文件的示例(显示约一半的列):
准备工作
下载 DMARC 聚合报告:从电子邮件中下载 DMARC 聚合报告附件。这些文件通常以
.xml.gz
或结尾.zip
,无需提取它们,因为 dmarcts-report-parser 会为您提取。- 注意:dmarcts-report-parser 可以配置为从 IMAP 服务器下载 DMARC 报告。出于安全考虑,我没有使用此功能。
- 提示:除了手动下载 DMARC 报告附件之外,还可以使用 Google Apps Script(我使用这个)、Microsoft Power Automate 和各种电子邮件客户端插件自动执行此操作。
创建工作文件夹:为了本次练习,我将创建一个名为的文件夹,
dmarcprocess
用于包含配置文件和最终的 csv 文件输出,以及一个名为的子文件夹,Reports
用于存储从步骤 1 下载的 DMARC 聚合报告。- 打开终端
mkdir ~/Documents/dmarcprocess
cd ~/Documents/dmarcprocess
mkdir Reports
- 将所有 dmarc 报告复制到
Reports
文件夹中
设置 MySQL 服务器
安装 MySQL:此步骤假设mysql服务器尚未安装。
sudo apt update
sudo apt install mysql-server
- 检查 msql 服务器是否处于活动状态:(
sudo service mysql status
使用 Ctrl-C 退出)。响应应为Active: active (running)
。如果不处于活动状态,请尝试sudo systemctl start mysql
。 - 推荐:
sudo systemctl disable mysql
阻止 mysql 在 PC 启动时自动启动并使用系统资源。您可以使用sudo systemctl start mysql
手动启动和sudo systemctl stop mysql
手动停止 mysql 服务器。 - 注意:mysql 服务器使用默认设置安装,不太安全(例如,
root
用户没有密码)。如果您打算在启动时自动启动 mysql 服务器,您可能需要稍后更改这些设置。
创建数据库和用户:我们将为 dmarcts-report-parser 创建默认数据库和默认用户。这些可以稍后自定义。
sudo mysql -u root -p
登录 mysql 服务器,然后在“输入密码:”提示符下按 Enter,因为没有root
密码。以下命令需要在mysql>
提示符下输入。我还包含了服务器应如何响应每个命令。CREATE DATABASE dmarc;
创建一个名为 dmarc 的新数据库。服务器响应:Query OK, 1 row affected
。USE dmarc;
连接到新创建的数据库。服务器响应:Database changed
。CREATE USER 'dmarc'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
创建新用户。服务器响应:Query OK
。GRANT ALL PRIVILEGES ON dmarc.* TO 'dmarc'@'localhost';
授予新用户对新数据库的完全访问权限。服务器响应:Query OK
。FLUSH PRIVILEGES;
重新加载权限。服务器响应:Query OK
。quit;
返回终端。
设置 dmarcts-report-parser
安装 dmarcts-report-parser
sudo apt install dmarcts-report-parser
配置 dmarcts-report-parser:将示例配置文件复制到工作文件夹中,然后编辑它。确保您位于
~/Documents/dmarcprocess/
以下命令的文件夹中。cp /usr/share/doc/dmarcts-report-parser/examples/dmarcts-report-parser.conf.sample ./dmarcts-report-parser.conf
复制并重命名示例配置文件。sed -i "s/'dbhost'/'localhost'/" ./dmarcts-report-parser.conf
将 mysql 服务器的名称更改为localhost
。
设置表并导出视图
首次运行 dmarcts-report-parser:dmarcts-report-parser 的第一次运行将创建数据库表,然后使用之前下载的 dmarc 报告填充数据库。
dmarcts-report-parser -z ./Reports/*
- 系统应该响应
Adding missing table <report> to the database.
并且Adding missing table <rptrecord> to the database.
这意味着 dmarcts-report-parser 需要的两个数据库表已经创建。 - 注意:
-z
用于根据项目页面。我发现此选项适用于.zip
和.xml.gz
文件。奇怪的是,此选项目前没有记录在Ubuntu 手册页。其他潜在文件类型包括 mbox (-m
)、MIME (-e
) 和 xml (-x
)。
创建数据库视图:数据库视图简化了数据的导出。
sudo mysql -u root -p
重新登录 mysql 服务器,然后在“输入密码:”提示符下按 Enter,因为没有root
密码。以下命令需要在mysql>
提示符下输入。我还介绍了服务器应如何响应每个命令。USE dmarc;
连接到新创建的数据库。服务器响应:Database changed
。CREATE VIEW exportview AS SELECT * FROM rptrecord INNER JOIN report USING (serial);
创建一个名为的新视图导出视图来自 dmarcts-report-parser 填充的两个表。quit;
返回终端。
导出数据及后续使用
导出数据:以下命令将使用 dmarc 数据导出到文件中
dmarc-report.csv
。它假定您在~/Documents/dmarcprocess/
文件夹中。mysql --user='dmarc' --password='password' --batch --execute='SELECT * FROM dmarc.exportview;' | sed 's/\xml.*/xml/;s/\t/","/g;s/^/"/;s/$/"/' > ./dmarc-report.csv
。- Mysql 将会抱怨,
mysql: [Warning] Using a password on the command line interface can be insecure.
但是该警告不会影响上述命令的结果。 - 新文件
dmarc-report.csv
是一个 CSV 文件,可以使用电子表格应用程序(例如 LibreOffice Calc)打开和分析。 - 此命令使用 MySQL 命令行客户端连接到数据库,将视图导出为 tsv 格式。然后
sed
删除 xml 输出,然后将提醒转换为 csv 格式。--execute=
执行以下语句并返回结果。--batch
使用制表符作为列分隔符打印结果。可以排除此选项,因为--execute
默认情况下它似乎执行相同的操作。sed 's/\xml.*/xml/;
删除“xml”后面的所有文本。这是必需的,因为数据库列之一(raw_xml)包含原始 xml 数据,这使得转换为 CSV 格式变得困难。如果有人有更好的方法,请告诉我。s/\t/","/g;
用 替换所有制表符,
。s/^/"/;
"
在每行的开头插入一个。s/$/"/'
"
在每行末尾插入一个。
后续使用
- 我不需要 mysql 一直运行,因此我用
sudo systemctl disable mysql
它来阻止 mysql 在重启时自动启动。 - 我使用 bash 批处理文件来自动解析和导入新报告并导出结果。
sudo systemctl start mysql
启动 mysql 服务器dmarcts-report-parser -z ./Reports/*
解析报告并将其存储在数据库中mysql --user='dmarc' --password='password' --batch --execute='SELECT * FROM dmarc.exportview;' | sed 's/\xml.*/xml/;s/\t/","/g;s/^/"/;s/$/"/' > ./dmarc-report.csv
导出文件。sudo systemctl stop mysql
导出完成后停止 mysql 服务器。
- 目前我每次都会导出所有内容,但在某些时候我可能会修改导出语句以仅导出我需要的数据,同时微调 dmarc、dkim 和 spf 设置。
- Ubuntu 手册页暗示dmarcts-报告查看器将来会由默认存储库支持。我打算在发生这种情况时更新此答案。
- 我不需要 mysql 一直运行,因此我用
请在评论中提供反馈以帮助改进此答案。
答案2
这是一个更轻量级的解决方案:
#!/usr/bin/env python3
import xml.etree.ElementTree as ET
import os.path
addresses = {}
dirname = os.path.expanduser("~/Documents/DMARC")
for basename in os.listdir(dirname):
if not basename.endswith(".xml"):
continue
tree = ET.parse(os.path.join(dirname, basename))
row = tree.find("record/row")
ip = row.find("source_ip").text
current = addresses.setdefault(ip, { "count": 0, "dmarc_pass": 0, "dmarc_fail": 0, "dkim_pass": 0, "dkim_fail": 0, "spf_pass": 0, "spf_fail": 0 })
current["count"] += int(row.find("count").text)
policy = row.find("policy_evaluated")
dkim_pass = policy.find("dkim").text == "pass"
spf_pass = policy.find("spf").text == "pass"
current["dkim_pass" if dkim_pass else "dkim_fail"] += 1
current["spf_pass" if spf_pass else "spf_fail"] += 1
current["dmarc_pass" if dkim_pass and spf_pass else "dmarc_fail"] += 1
print("ip_address,email_volume,dmarc_pass,dmarc_fail,dmarc_rate,spf_pass,spf_fail,dkim_pass,dkim_fail")
for ip, current in addresses.items():
dmarc_pass = current["dmarc_pass"]
dmarc_fail = current["dmarc_fail"]
print(f'{ip},{current["count"]},{dmarc_pass},{dmarc_fail},{dmarc_pass/dmarc_fail}%,{current["spf_pass"]},{current["spf_fail"]},{current["dkim_pass"]},{current["dkim_fail"]}')
将其保存到dmarc.py
,chmod +x dmarc.py
。使用 运行它./dmarc.py > dmarc.csv
。我只是猜测 DMARC XML 文件格式应该如何工作,因此可能需要进行调整。
示例输出
ip_address,email_volume,dmarc_pass,dmarc_fail,dmarc_rate,spf_pass,spf_fail,dkim_pass,dkim_fail
203.0.113.209,2,0,1,0.0%,1,0,0,1