什麼是 DMARC 報告
DMARC 代表網域型郵件認證、報告和符合性。它是一項電子郵件認證通訊協定,可幫助防範電子郵件網路釣魚和詐騙。
傳送電子郵件時,DMARC 允許網域擁有者設定 DNS 記錄,指定用於驗證電子郵件真實性的認證方法,如 SPF(寄件者原則架構)和 DKIM(網域金鑰識別郵件)等。當電子郵件未通過這些認證檢查時,DMARC 會指示收件者的電子郵件提供者如何處理郵件:隔離郵件或直接拒絕郵件。
如今,在網際網路中,電子郵件網路釣魚和詐騙攻擊越來越複雜且普遍,因此 DMARC 的重要性也日漸提升。透過實作 DMARC,網域擁有者能夠保護他們的品牌和客戶不受這些攻擊的負面影響,包括失去信任、信譽損害和經濟損失。
除了針對網路釣魚和詐騙攻擊提供保護,DMARC 還提供報告功能。網域擁有者能夠接收有關電子郵件認證活動的報告,其中包括哪些訊息通過了 DMARC 檢查,哪些未通過,以及這些訊息的來源。
DMARC 管理功能涉及設定和維護網域的 DMARC 原則。若要實現有效的 DMARC 管理功能,需對電子郵件認證活動進行持續的監控和分析,以及能夠根據需要對 DMARC 原則進行調整和更新。
以下為有效 DMARC 管理功能的幾個關鍵組成部分:
設定 DMARC 原則:此操作涉及設定網域的 DMARC 記錄,以指定合適的認證方法和原則,用於處理未通過認證檢查的訊息。以下展示了 DMARC DNS 記錄外觀:
v=DMARC1; p=reject; rua=mailto:[email protected]
這指定了我們將使用 DMARC 版本 1,我們的原則是拒絕未通過 DMARC 檢查的電子郵件,以及提供者應向其傳送 DMARC 報告的電子郵件地址。
監控電子郵件認證活動:DMARC 報告對於網域擁有者來說是一項重要工具,有助於他們確保電子郵件的網路安全和可寄送性以及符合行業標準和法規。透過定期監控並分析 DMARC 報告,網域擁有者能夠識別電子郵件威脅、最佳化電子郵件活動,並改進電子郵件認證的整體效果。
根據需要進行調整:根據 DMARC 報告的分析結果,網域擁有者可能需要調整 DMARC 原則或認證方法,以確保能夠正確認證電子郵件訊息,免受網路釣魚和詐騙攻擊。
與電子郵件提供者和協力廠商合作:若要實現有效的 DMARC 管理功能,可能需要與電子郵件提供者和協力廠商協同合作,以確保 DMARC 原則得到正確地實作和執行。
現在,我們推出了 DMARC 管理功能。以下說明了它的建構方式。
如何構建
Cloudflare 作為雲端式網路安全和效能解決方案的領先提供者,採取了特定的方法來測試我們的產品。我們「吃自產的狗糧」,這表示我們使用自己的工具和服務來執行我們的商業方案。這有助於我們提前識別任何問題或錯誤,避免它們影響到客戶。
我們在內部使用自己的產品,例如 Cloudflare Workers,這是一個無伺服器平台,允許開發者在我們的全球網路上執行他們的程式碼。自 2017 年推出以來,Workers 生態系統發展迅速。如今,有成千上萬的開發者在該平台上建構和部署應用程式。Workers 生態系統的強大之處在於,它能夠讓開發者建構複雜的應用程式,而這些應用程式之前的執行不可能距離用戶端如此近(或不切實際)。Workers 可用於建構 API、產生動態內容、最佳化影像、執行即時處理等等。可能性幾乎是無限的。我們使用 Workers 為 Radar 2.0 等服務或 Wildebeest 等軟體套件提供支援。
最近,我們的 Email Routing 產品與 Workers 聯手,可以透過 Workers 指令碼處理傳入的電子郵件。正如文件所述:「借助 Email Workers,您可以利用 Cloudflare Workers 的強大功能來實作處理電子郵件和建立複雜規則所需的任何邏輯。這些規則決定了收到電子郵件時會執行的操作。」規則和驗證的地址都可以透過我們的 API 設定。
以下展示了簡單的 Email Worker 外觀:
很簡單,對吧?
export default {
async email(message, env, ctx) {
const allowList = ["[email protected]", "[email protected]"];
if (allowList.indexOf(message.headers.get("from")) == -1) {
message.setReject("Address not allowed");
} else {
await message.forward("inbox@corp");
}
}
}
鑒於能夠以程式設計方式處理傳入的電子郵件,它似乎是以可擴展和高效的方式處理傳入 DMARC 報告電子郵件的最佳方式,讓 Email Routing 和 Workers 完成接收全球無數電子郵件的繁重工作。以下是對我們所需操作的詳細說明:
接收電子郵件並擷取報告
將相關詳細資料發佈到分析平台
儲存原始報告
憑藉 Email Workers,我們能夠輕鬆完成 #1。我們只需建立一個帶有 email() 處理常式的 Worker。此處理常式將接收 SMTP 信封元素、預解析版本的電子郵件標頭以及用於讀取整個原始電子郵件的資料流。
對於 #2,我們還可以查看 Workers 平台並找到 Workers Analytics Engine。我們只需要定義一個合適的架構,這取決於報告中的內容和我們計劃稍後進行的查詢。之後我們可以使用 GraphQL 或 SQL API 查詢資料。
對於 #3,我們只需要使用我們的 R2 物件儲存體。從 Worker 存取 R2 非常簡單。從電子郵件中擷取報告之後,我們會將這些報告儲存在 R2 中。
我們將其建構為您可以在您的區域啟用的託管服務,為方便起見,還新增了一個儀表板介面,但實際上所有工具都可供您使用,以在您自己的帳戶中在 Cloudflare Workers 之上部署您自己的 DMARC 報告處理器 ,無需擔心伺服器、可擴展性或效能。
架構
Email Workers 是我們 Email Routing 產品的一項功能。Email Routing 元件在我們所有的節點中執行,因此它們中的任何一個都能夠處理傳入郵件,這很重要,因為我們從所有數據中心公佈了電子郵件輸入 BGP 首碼。向 Email Worker 傳送電子郵件就像在 Email Routing 儀表板中設定規則一樣簡單。
當 Email Routing 元件收到一封電子郵件,該郵件與要傳遞給 Worker 的規則相匹配時,它將聯絡我們最近開源的 workerd 執行階段的內部版本,該執行階段也在所有節點上執行。管理此互動的 RPC 架構在 Capnproto 架構中定義,並允許在閱讀電子郵件正文時將其流式傳輸到 Edgeworker。如果 Worker 指令碼決定轉送此電子郵件,Edgeworker 將使用原始請求中傳送的功能聯絡 Email Routing。
在 DMARC 報告的內容中,以下是我們處理傳入電子郵件的方式:
jsg::Promise<void> ForwardableEmailMessage::forward(kj::String rcptTo, jsg::Optional<jsg::Ref<Headers>> maybeHeaders) {
auto req = emailFwdr->forwardEmailRequest();
req.setRcptTo(rcptTo);
auto sendP = req.send().then(
[](capnp::Response<rpc::EmailMetadata::EmailFwdr::ForwardEmailResults> res) mutable {
auto result = res.getResponse().getResult();
JSG_REQUIRE(result.isOk(), Error, result.getError());
});
auto& context = IoContext::current();
return context.awaitIo(kj::mv(sendP));
}
擷取正在處理的電子郵件的收件者,這是使用的 RUA。RUA 是一個 DMARC 設定參數,指示應在何處報告與某個網域相關的彙總 DMARC 處理回饋意見。可以在訊息的「to」屬性中找到此收件者。
const ruaID = message.to
由於我們處理無數網域的 DMARC 報告,因此我們使用 Workers KV 來儲存每個網域的一些相關資訊,並在 RUA 上鍵入這些資訊。透過該操作,我們也能知道是否應該接收這些報告。
const accountInfoRaw = await env.KV_DMARC_REPORTS.get(dmarc:${ruaID})
此時,我們想要將整封電子郵件讀入 arrayBuffer 以便對其進行解析。根據報告的大小,我們可能會受到免費 Workers 計劃的限制。如果發生這種情況,建議您切換到 Workers Unbound 資源模型,該模型不會出現此問題。
const rawEmail = new Response(message.raw) const arrayBuffer = await rawEmail.arrayBuffer()
解析原始電子郵件包括解析其 MIME 部分等。有多個可用的庫可執行此操作。例如,您可以使用 postal-mime:
const parser = new PostalMime.default() const email = await parser.parse(arrayBuffer)
解析電子郵件後,現在我們可以存取其附件。這些附件是 DMARC 報告本身,可以被壓縮。我們要做的第一件事是將它們以壓縮形式儲存在 R2 中以進行長期儲存。稍後重新處理或調查目標報告時可能會用到它們。此操作就像在 R2 繫結上叫用 put() 一樣簡單。為了便於以後擷取,建議您將報告檔案按目前時間分佈在不同的目錄中。
await env.R2_DMARC_REPORTS.put(
${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${attachment.filename}
, attachment.content )現在我們需要查看附件 mime 類型。DMARC 報告的原始格式是 XML,但它們可以被壓縮。在這種情況下,我們需要先解壓它們。DMARC 報告程式檔案可以使用多種壓縮算法。我們使用 MIME 類型來了解使用哪一種。Zlib 壓縮報告可以使用 pako ,而對於 ZIP 壓縮報告,unzipit 是一項不錯的選擇。
獲得報告的原始 XML 格式後,fast-xml-parser 在解析它們時效果很好。以下展示了 DMARC 報告 XML 外觀:
現在,我們可以輕鬆取得報告中的所有資料。後續我們要執行的動作在很大程度上取決於我們想要如何呈現資料。我們的目標是在儀表板中顯示從報告中擷取的有意義的資料。因此,我們需要一個分析平台,可以在其中推送豐富的資料。進入 Workers Analytics Engine。Analytics 引擎非常適合這項工作,因為透過該引擎,我們可以從 Worker 向它傳送資料,然後公開 GraphQL API 以與資料互動。這就是我們獲取資料以在儀表板中顯示的方式。
未來,我們還會考慮在工作流程中整合 Queues,以異步處理報告,避免等待用戶端完成此過程。
const ruaID = message.to
我們成功地僅依靠 Workers 基礎結構端到端地實作了這個專案,證明了建構重要應用程式的可能性和優勢,而不必擔心可擴展性、效能、儲存和網路安全問題。
const accountInfoRaw = await env.KV_DMARC_REPORTS.get(dmarc:${ruaID})
開源
const rawEmail = new Response(message.raw)
const arrayBuffer = await rawEmail.arrayBuffer()
正如我們之前提到的,我們建構了一個您可以啟用和使用的託管服務,我們將為您管理它。但是,我們所做的一切也可以由您在您的帳戶中部署,以便您可以管理自己的 DMARC 報告。過程簡單,而且免費。為了幫助您執行此操作,我們發佈了一個開源版本的 Worker,它以上述方式處理 DMARC 報告:https://github.com/cloudflare/dmarc-email-worker
const parser = new PostalMime.default()
const email = await parser.parse(arrayBuffer)
如果您沒有用於顯示資料的儀表板,您還可以從 Worker 查詢 Analytics Engine。或者,如果您想將它們儲存在關係資料庫中,則可以使用 D1。可能性是無限的,我們期待看到您將使用這些工具建構什麼。
await env.R2_DMARC_REPORTS.put(
`${date.getUTCFullYear()}/${date.getUTCMonth() + 1}/${attachment.filename}`,
attachment.content
)
請分享您自己的想法,我們洗耳恭聽。
<feedback>
<report_metadata>
<org_name>example.com</org_name>
<[email protected]</email>
<extra_contact_info>http://example.com/dmarc/support</extra_contact_info>
<report_id>9391651994964116463</report_id>
<date_range>
<begin>1335521200</begin>
<end>1335652599</end>
</date_range>
</report_metadata>
<policy_published>
<domain>business.example</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
<pct>100</pct>
</policy_published>
<record>
<row>
<source_ip>192.0.2.1</source_ip>
<count>2</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>business.example</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>business.example</domain>
<result>fail</result>
<human_result></human_result>
</dkim>
<spf>
<domain>business.example</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>
結束語
我們希望這篇文章能加深您對 Workers 平台的理解。如今,Cloudflare 利用此平台建構了我們的大部分服務,我們認為您也應該這麼做。
歡迎使用我們的開源版本,向我們展示您可以使用它實現哪些目的。
Email Routing 也在努力擴展 Email Workers API 的功能,我們很快會在另一篇部落格文章中進行介紹。