跳至主要內容
技術

SPF / DKIM / DMARC 到底在幹嘛?三個 DNS 記錄一次搞懂

誰在冒用你的 Domain 寄信 第 2 / 4 篇 ,前往系列總覽

本篇是「誰在冒用你的 Domain 寄信」系列的第 2 / 4 篇。你可以從系列總覽開始閱讀,也可以直接接著看本文。

你有沒有想過:為什麼詐騙集團能寄出一封「看起來真的來自某銀行」的信?

因為 email 有個先天缺陷——寄件人地址(From)可以隨便填,就像實體信封上的寄件人欄,你想寫誰就寫誰。SMTP 協定誕生的年代沒人想到要防偽。

於是後來補了三道關卡:SPF、DKIM、DMARC。它們都是你網域 DNS 裡的幾筆記錄,合起來回答三個問題:誰能幫我寄信?信有沒有被動手腳?驗不過時收件方該怎麼辦?

這篇用「寄一封實體掛號信」的比喻,把這三個一次講清楚。

📎 這是「誰在冒用你的 Domain 寄信」系列的入門篇。系列起點是一篇真實案例:我如何重現一個資安評等的 F;讀完想動手把 DMARC 推到 p=reject,接 #3 實戰 playbook;想看真的按下去那天發生什麼事,看 #4 執行日記錄

先看全貌:一封信抵達的那幾秒鐘

在拆解三個記錄之前,先看一眼它們合起來長什麼樣。一封信寄到收件伺服器,大約是這樣跑完的:

flowchart TD
    MAIL["一封信抵達收件伺服器<br/>From: bobo@yourdomain.com"]
    MAIL --> SPF["① SPF<br/>送信來的伺服器<br/>在你的白名單上嗎"]
    MAIL --> DKIM["② DKIM<br/>信上的火漆印<br/>驗得過嗎"]
    SPF --> ALIGN["③ 對齊<br/>通過的那個網域<br/>跟 From 顯示的算同一家嗎"]
    DKIM --> ALIGN
    ALIGN -->|任一邊通過且對齊| PASS["DMARC pass<br/>照常收下"]
    ALIGN -->|兩邊都沒過| POLICY{"去查 _dmarc<br/>你的 p= 寫什麼"}
    POLICY -->|"p=none"| NONE["照收,只寫進報表"]
    POLICY -->|"p=quarantine"| QUAR["丟垃圾郵件匣"]
    POLICY -->|"p=reject"| REJ["直接退回"]

三件事值得先記住:

  • SPF 和 DKIM 是兩條各自獨立的路,誰過誰不過互不影響。
  • 兩條路的終點都是「對齊」——這是 DMARC 才有的關卡,也是全篇最難的一段,我後面用一整節講。
  • 只要其中一條走到底,DMARC 就算過(這是 OR 邏輯,不是 AND)。這個設計等一下講「轉寄」的時候會救你一命。

SPF:誰可以幫我寄信(郵差白名單)

比喻:你公告「只有 A、B、C 這三家快遞,能用我公司的名義寄件」。郵局收到信,先看寄件方是不是名單上的。

技術:SPF 是一筆 DNS TXT,列出被授權的寄信伺服器。收件方檢查「這封信是不是從名單上的伺服器來的」。

flowchart LR
    SEND["寄信的伺服器<br/>209.85.220.41"] -->|把信交出來| RECV["收件伺服器"]
    RECV -->|"查 TXT yourdomain.com"| DNS["你公告的白名單<br/>v=spf1 include:_spf.google.com ~all"]
    DNS --> Q{"這個 IP<br/>在名單上嗎"}
    Q -->|在| OK["SPF pass"]
    Q -->|不在| NG["照結尾的 all 機制處理<br/>~all 收下但標記 / -all 拒收"]

範例:v=spf1 include:_spf.google.com ~all(用 Google Workspace 寄,其餘 softfail)。

這裡先記一個細節,後面講轉寄會用到:SPF 看的是「站在門口把信交出來的那台機器」,不是信本身。信的內容它一個字都不看。

結尾那個 all 機制最關鍵——它決定「名單以外的人來」時怎麼辦:

寫法意思防偽力
+all放行任何人等於沒設(危險)
?allneutral(中性)幾乎沒用
~allsoftfail(收下但標記)
-allhardfail(拒絕)

⚠️ 陷阱:SPF 有「10 次 DNS 查詢」上限,include 串太多會讓整筆 SPF 失效。

DKIM:這封信確實是我、且沒被竄改(火漆印)

比喻:你在信封封口蓋一個只有你有的火漆印章;對方比對印模,就知道是不是你寄的、有沒有被中途拆過。

技術:寄件伺服器用私鑰對信件簽章,公鑰放在 DNS(selector._domainkey.你的網域)。收件方用公鑰驗章。

flowchart LR
    A["寄件伺服器<br/>用私鑰在信上蓋章"] --> B["信帶著火漆印上路<br/>DKIM-Signature 標頭<br/>d=yourdomain.com、s=google"]
    B --> C["收件伺服器<br/>照 s= 去查<br/>google._domainkey.yourdomain.com<br/>拿到公鑰"]
    C --> D{"印模對得上?<br/>內容也沒被改?"}
    D -->|是| OK["DKIM pass<br/>確實是你寄的<br/>而且途中沒被動手腳"]
    D -->|否| NG["DKIM fail"]

它同時證明兩件事:信來自持有私鑰的人 + 內容沒被中途改過。

範例:Google Workspace 的 selector 是 google,所以公鑰在 google._domainkey.你的網域

信被轉寄一次:SPF 壞了,DKIM 沒事

這是入門讀者最容易踩到、卻很少有人先講的一件事,而且它直接解釋了為什麼 DMARC 要設計成 OR 邏輯。

SPF 檢查的是「站在門口把信交出來的是誰」。信只要被轉寄一次——同事設了自動轉信、或信寄進一個郵件群組再發給所有成員——最後把信交到收件伺服器手上的,就是那台轉寄主機。它當然不在你的 SPF 名單上,SPF 就 fail 了。不是信被改壞,是交信的人換了。

DKIM 不一樣。火漆印是壓在信上、跟著信走的。中間換手幾次都還在,只要沒人去動信的內容和被簽章的那些標頭,公鑰照樣驗得過。

flowchart TD
    subgraph DIRECT["情境 A:直達"]
        direction LR
        S1["你的寄件伺服器"] --> R1["收件伺服器"]
        R1 --> V1["SPF ✓ 交信的 IP 在名單上<br/>DKIM ✓ 火漆印驗得過"]
    end
    subgraph FWD["情境 B:中途被轉寄一次"]
        direction LR
        S2["你的寄件伺服器"] --> F2["轉寄主機<br/>個人自動轉信 / 郵件群組"]
        F2 --> R2["最終收件伺服器"]
        R2 --> V2["SPF ✗ 交信的是轉寄主機<br/>不在你的名單上<br/>DKIM ✓ 火漆印跟著信走,還在"]
    end

這個差別在 p=none 的時候完全看不出來(反正什麼都不會被擋)。但一旦走到 p=reject,它就是最常見的真實災情:轉寄信和郵件群組被退回

也因為這樣,DMARC 才規定「SPF 或 DKIM 任一邊對齊通過就算過」——DKIM 是信被轉寄之後,唯一還活著的那道

DMARC:驗不過時怎麼辦 + 給我報告(處置政策)

比喻:前兩關是「檢查」,DMARC 是「公司規定」——萬一掛號信驗不過,是退回、丟到一旁、還是照收?順便每天給你一份「今天有多少冒名信」的報表。

技術:DMARC 是 _dmarc.你的網域 的 TXT,做三件事:

  1. 政策 p=:none(只觀察)、quarantine(丟垃圾桶)、reject(直接拒收)。
  2. 對齊(alignment):光 SPF/DKIM 通過還不夠,被驗過的那個網域要和 From 顯示的網域「對得起來」才算數。這是 DMARC 比單獨 SPF/DKIM 強的關鍵,下一節整節都在講它。
  3. 報告 rua=:把每日彙整報告寄到你指定的信箱。沒有 rua,你等於瞎子。

那三個 p= 的差別,用門來想最快:

flowchart LR
    FAIL["一封 DMARC 驗不過的信<br/>可能是冒名<br/>也可能是你自己漏設的合法信"] --> P{"你的 p= 寫什麼"}
    P -->|"p=none"| N["門開著<br/>信照樣進收件匣<br/>只在報表裡記一筆"]
    P -->|"p=quarantine"| Q["門虛掩<br/>丟進垃圾郵件匣<br/>收件人翻得到"]
    P -->|"p=reject"| R["門鎖上<br/>連收都不收,直接退回<br/>收件人完全不知道有這封信"]

範例:v=DMARC1; p=none; rua=mailto:dmarc@你的網域; adkim=r; aspf=r

adkim=r; aspf=r 其實是預設值,不寫也一樣。我還是把它寫出來,純粹是為了讓後面接手的人看到它、知道它是刻意留的——避免有人手癢改成 s(下一節會講為什麼它的代價遠大於收益)。

注意:p=none 沒有保護力,只是觀察;真正擋冒名要走到 p=quarantine/reject——但中間有眉角,所以才有 #3 playbook

📌 查資料時的小提醒:DMARC 的規範在 2026-05 由 RFC 9989 取代了舊的 RFC 7489,正式升為 Standards Track。網路上大量文章還是照 RFC 7489 在寫,看到的時候記得它已經是舊版。對上線流程最直接的影響是 pct 標籤被移除了,#3 有整理該怎麼改用政策階梯漸進。

對齊(alignment):姓氏規則

這是整個系列最難懂的一段,值得慢慢講。

問題出在:「信封上的名字」和「火漆印上的名字」不一定會一樣。

因為現實裡,你的信常常是外包出去寄的——電子報交給 Mailchimp、交易信和系統通知交給 Mailgun。這類服務幫你寄的時候,很常是掛在你的子網域底下(像 mg.yourdomain.com),而不是主網域本身。

於是變成這樣:

  • 信封上寫「陳家公司」(收件人看到的 From 是 @yourdomain.com)
  • 火漆印上寫「陳家公司・第三分部」(DKIM 的 d=mg.yourdomain.com)

DMARC 要判斷「這兩個到底算不算同一家」,有兩套規則:

信封上寫的名字(收件人看到的 From) 火漆印上寫的名字(DKIM 的 d=) 陳家公司 陳家公司・第三分部 From: bobo@yourdomain.com d=mg.yourdomain.com 粗線標的是「姓」——外包寄信時,火漆印上常常會多一個「分部」(子網域)。 同一封信,兩套規則判出兩種結果: 寬鬆 relaxed(預設值) 嚴格 strict adkim=r / aspf=r adkim=s / aspf=s 只看姓: 要一模一樣: 陳家 = 陳家 陳家公司 ≠ 陳家公司・第三分部 ✓ 對齊通過 ✗ 對齊失敗 幾乎所有公司的信都靠這條活著 擋掉的幾乎都是自家的電子報、帳單、密碼重設信
對齊就是一條姓氏規則:預設只看姓,同姓就算同一家;改成嚴格,連分部都得一字不差。
  • 寬鬆 relaxed(adkim=r / aspf=r,預設):只看姓。同姓就算同一家,通過。
  • 嚴格 strict(adkim=s / aspf=s):要一模一樣,連分部都得對上,不通過。

這裡最該記住的一句:幾乎所有公司的信,都是靠「只看姓」這條預設規則活著的。

為什麼「改成嚴格」幾乎沒有收益,代價卻很大

看到 r 這個預設值,很多人的直覺反應是「這聽起來很鬆,收緊一點應該更安全」。

不會。把它改成 s,擋不掉一般的冒名信

偽造信從來就不是任何一個「陳家」簽的——它們用的是自己的網域、自己的鑰匙,連姓都不一樣。在寬鬆規則下,它們本來就已經在失敗了。收緊姓氏規則,對它們的處境沒有造成任何改變。

你多擋掉的,幾乎都是自己的電子報、帳單、密碼重設信——那些真的姓陳、只是名字後面掛了分部的信。

唯一的例外寫在 RFC 9989 §11.8:如果你的某個子網域 DNS 委派給了別人、或哪天被接管,寬鬆規則會讓那個子網域簽出來的信也算「同姓」而通過。嚴格規則擋得掉這一種。但那本質上是子網域治理問題,而代價是自家所有掛子網域的寄件管道一起陣亡——先把子網域管好,通常划算得多。

所以預設的 r 不是「還沒調好」,是「應該留著」。

(補一句給想追細節的人:因為 DMARC 是 OR 邏輯,只把其中一個 tag 改成 s 未必當場出事——要 SPF 和 DKIM 兩邊都被收緊、而寄信管道剛好兩邊都掛在子網域上,才會整批掛掉。真的長成這樣的一條管道、以及在 p=reject 上線那天為什麼決定不去動它,記在 #4。)

三個一起看

  • SPF 管「從哪台機器寄」、DKIM 管「內容真偽」、DMARC 管「驗不過怎麼辦 + 回報」。
  • 三者缺一不可:只有 SPF/DKIM 沒 DMARC,冒名信還是進得來;有 DMARC 但停在 p=none,等於裝了監視器卻不鎖門。
  • 對齊是把前兩者和 From 綁在一起的那條線——沒有它,詐騙集團大可用自己的網域簽一封 DKIM 完全通過的信,然後在 From 寫你的名字。

30 秒自我檢查

dig +short TXT yourdomain.com | grep spf1           # 有 SPF 嗎?結尾是 -all 還是 ?all?
dig +short TXT _dmarc.yourdomain.com                # 有 DMARC 嗎?p= 是什麼?
dig +short TXT google._domainkey.yourdomain.com     # (Google Workspace) DKIM 設了嗎?

懶得記指令的話,mxtoolboxdmarcianinternet.nl 都能一鍵體檢。

為什麼要在意

  • 防冒名釣魚:保護你的客戶、員工不被社交工程。
  • 保護品牌:沒人能假冒你寄垃圾信。
  • 送達率:認證齊全的網域,信比較不會被丟進垃圾桶。

這三個記錄是「設定」不是「開發」,改 DNS 就好,技術門檻其實很低——難的從來不是技術,是把它排進待辦。真的要動手把 DMARC 安全推到 reject,接著看 #3 實戰 playbook;想先看看真的按下去那天會遇到什麼,看 #4 執行日的假訊號

留言討論

esc
輸入關鍵字搜尋文章...
查看收藏 →