你的郵件 client 開機後做的第一件事,是去問 DNS「我的 SMTP 伺服器在哪」。如果沒人替這個答案簽名,攻擊者就能回你一個假地址,而你連上去的那一刻,TLS 還是會亮出一把綠色的鎖——鎖是真的,連到的人是假的。
忽視 DNSSEC,等於替 MITM 鋪好一條路
這篇文章想講清楚一件反直覺的事:在 TLS 完全正常、憑證完全有效、瀏覽器或郵件 client 沒有任何警告的情況下,一個攻擊者仍然可以站在你和伺服器中間,把你的帳號密碼與郵件全部讀走。關鍵不在 TLS 被破解,而在 TLS 之前那一步——你怎麼知道「該連到哪台機器」。這一步靠 DNS,而絕大多數作業系統與發行版預設不驗證 DNS 回應的真偽。Hugo Barrera 在文章裡把這個破綻攤開,從一段 2010 年的親身經歷講起,逐一拆解它對 email、Matrix、XMPP 的不同結局,最後給出一個你今晚就能套用的結論。讀完你會知道 DNS 欺騙是怎麼在 TLS 仍成立的情況下完成 MITM 的,以及為什麼「信任一台第三方解析器」不是解法。
2010 年,我們在內網裡看見了同事的 MSN 訊息
故事的起點不是協定規格,是一次內網實驗。Barrera 寫道,大約在 2010 年,他和同事在公司網路上玩 ARP poisoning,攔截流向其他主機的流量。結果是立刻看見整個網路的流量在眼前流過,而在那一堆資料中間,他們瞥見了幾位同事透過 MSN Messenger 跟家人聊天的訊息片段。他的原話是「we caught a glace of bits of messages of a few colleagues talking to their families over MSN Messenger」,並補一句這經驗令人不安。他們不是想監視誰,只是想搞懂自家網路的安全性,但東西就這麼出現了。
這段經歷的份量在於:MITM 不是黑板上的威脅模型,是肉眼能看見的東西。而且當年的門檻低到荒謬。Barrera 提到,hub 和開放 Wi-Fi 在那個年代還很常見,在那種環境上側聽流量「連 ARP poisoning 都不需要」,純粹被動聽就行。攔截不是高深技術,是預設不設防的後果。
正是這段經歷讓他在差不多同個時期理解了 HTTPS 的意義。一旦你把服務暴露給 client 或所愛的人,就得用 TLS 確保連線安全,這在他看來是顯而易見的。問題是,HTTPS 在當年並不是一路順風。
反對 DNSSEC 的話,和當年反對 HTTPS 的一字不差
Barrera 把當年反對 HTTPS 的論點原樣列了出來,而這正是他整篇文章的論證骨架。那些理由是這樣的:太複雜,失敗時很難除錯;萬一弄錯,服務就連不上;憑證得即時續期,不然服務會掛;它增加額外開銷和延遲。他的總結很直白——反對 HTTPS 的論點「always the same」,多半建立在恐懼,以及一種他覺得可以理解的經驗不足之上。
然後是那句把過去與現在縫在一起的話:「These are the exact same arguments that I hear against DNSSEC every time the topic comes up.」每次有人提起 DNSSEC,他聽到的反對理由跟當年反 HTTPS 的完全一樣。複雜、難除錯、做錯就連不上、簽章管理麻煩、增加延遲——換個主詞,同一套說辭。
這個類比之所以有力,不只是修辭。它提醒你 HTTPS 後來的結局:那些反對理由沒有一條消失,HTTPS 還是贏了,因為攔截的代價遠高於管理憑證的代價。Barrera 的暗示是,DNSSEC 此刻站在 HTTPS 當年站過的同一個位置。先別急著接受這個結論,先看清楚 DNSSEC 到底在防什麼——也就是 DNS 不設防時,攻擊具體怎麼發生。
為什麼 TLS 沒擋住:你驗的是「連到的那台」,不是「本該連的那台」
先把一條容易被跳過的事實放回桌面。現代的郵件 client 不會要你手動填 IMAP 與 SMTP 伺服器位址。Barrera 描述的流程是:你給 client 你的 email 和密碼,client 自動用 SRV record 解析出 IMAP 和 SMTP 伺服器,然後連上去。背景上,SRV record 是一種 DNS 記錄,作用是讓某個網域宣告「我這個服務跑在哪台主機、哪個 port」,於是 client 不必寫死位址,問 DNS 就好。方便,但也意味著「該連到哪台機器」這個決定,完全交給了 DNS 的回應。
破綻就在這裡。Barrera 寫道,如果你沒在用 DNSSEC,攻擊者可以偽造這些 DNS 回應,把你的郵件 client 指向 smtp.evilattacker.com。接下來是最反直覺的一句,照原文是「the TLS handshake succeeds just fine: the server properly presents a certificate for smtp.evilattacker.com」。TLS 握手完全成功,因為那台攻擊者的伺服器,正當地出示了一張屬於 smtp.evilattacker.com 的憑證。
把這句話拆開來看。TLS 憑證證明的是「你現在連著的這台機器,確實是 smtp.evilattacker.com」——而它確實是。憑證鏈完整、簽發機構可信、域名相符,每一項檢查都通過。TLS 從頭到尾在認真工作,它只是在回答一個你沒打算問的問題:你連到的那台,是不是它自稱的那台。它不會、也無法回答另一個問題:你連到的那台,是不是你本該連的那台。後者的答案藏在 DNS 那一步,而那一步沒有任何人簽名背書。
很多人對 TLS 的直覺是「它保證我跟正確的伺服器之間沒人能插手」,這句話只對了一半。TLS 保證的是「我跟『某台機器』之間沒人能插手,而且那台機器確實是它聲稱的身分」。至於那台機器是不是你真正想連的對象,TLS 不負責、也無從負責——它在握手時看到的,只是 DNS 早已替你決定好的那個目標。把選址交給沒設防的 DNS,等於先讓攻擊者挑好你要連的人,再請 TLS 去認真確認「你連的這個人確實叫這個名字」。名字當然對,因為那個名字就是攻擊者註冊的。
這就是 DNSSEC 補上的環節。DNSSEC 替 DNS 回應加上密碼學簽章,讓解析器能驗證「這個 SRV 答案真的來自該網域的權威伺服器,沒被中途換掉」。背景上,這層簽章驗的不是內容對不對,而是來源真不真——它確保你拿到的是該網域真正發布的記錄,而不是攻擊者塞進來的。沒有這層驗證,TLS 再嚴謹也只是在替一個被掉包過的目標把關。下面這個分頁把整起 SMTP 攔截拆成四個階段,你會看到每一階段 TLS 為什麼都挑不出毛病。
你填好 email 與密碼,client 為了找 SMTP 伺服器,向 DNS 查詢該網域的 SRV record。它沒有寫死任何位址,完全等 DNS 告訴它「該連去哪」。此刻一切正常。
TLS 還沒登場。此刻唯一的信任根據,是 DNS 那個答案的真偽。
攻擊者在這條路徑上偽造 DNS 回應。因為沒人替答案簽名,解析器無從分辨真假,把假答案原樣交給 client。SRV record 指向的主機名,從你真正的供應商,被換成了 smtp.evilattacker.com。
換掉的只是一個主機名。client 完全不知道答案被動過手腳。
client 連上 smtp.evilattacker.com,開始 TLS 握手。攻擊者那台伺服器出示一張屬於 smtp.evilattacker.com 的合法憑證——這張憑證鏈完整、域名相符、簽發機構可信。TLS 的每一項檢查都通過,沒有任何警告。
綠鎖是真的。TLS 沒出錯,它只是回答了你沒打算問的那個問題。
連線建立完成,client 把帳號密碼送過去登入,接著把郵件交給這台伺服器收發。Barrera 指出,盯著伺服器名稱的人或許還能察覺異狀;但若攻擊者用的是 smtp.gmaill.tech 這種近似冒充,而你用的是 Gmail,就難多了。對沒聽過 DNSSEC 的人,這類攻擊「entirely invisible」。
四步走完,沒有一個警告框跳出來。整起攻擊靠的就是 DNS 那一步沒人簽名。
有一個數字要特別標出來免得誤讀。Barrera 說對「沒聽過 DNSSEC 的人,也就是 99% 的人類」而言這些攻擊完全不可見——這個 99% 是他的修辭誇飾,不是量測數字,原文是放在 i.e. 後面的隨手一筆,引用時別當成統計值看待。它要傳達的只是一件事:受影響的人遠多於知道這件事的人。
把這四步收成一張靜態圖看,差別會更清楚:差的不是 TLS 那一段,是 TLS 之前的選址那一段。下面這張圖把「不驗 DNSSEC」與「驗 DNSSEC」兩條路徑並排,紅綠對照之處正是整個機制的支點。
靜態對照圖 · 兩條解析路徑 × 四個步驟
同一個破綻,email、Matrix、XMPP 為何結局不同
到此為止講的都是郵件 client 收信那一側(走 SRV)。但 email 有兩側,伺服器之間寄信是另一側,而它走的是另一種 DNS 記錄。Barrera 描述:一台伺服器要寄信給另一台時,靠查詢對方網域的 MX record 找到收信伺服器。同樣地,當他的伺服器去 DNS 查收件人的 MX 伺服器時,攻擊者可以毒化回應,於是他的伺服器就連到攻擊者的伺服器去了。
不過寄送端的結局沒那麼乾脆。Barrera 在這裡用了軟化的措辭:攻擊者的伺服器「likely won't be able to forward intercepted traffic」,原因和反垃圾規則的運作方式有關,所以這種攻擊會留下較多證據——因為信件沒被正常投遞。但他緊接著補一句,它「still perfectly feasible」。注意這裡的 likely,是他自己的不確定,不是定論;可行性則是斷言。寄送端比收信端更容易被察覺,但破綻照樣在。
這個收信端與寄送端的不對稱值得多想一層。收信那一側,攻擊者只要把流量靜靜複製一份、再原樣轉給真正的伺服器,你的信照常收得到,神不知鬼不覺,所以特別危險。寄送那一側,攻擊者攔下了你伺服器交出去的信,卻往往沒辦法再以你的名義把它轉投到真正的目的地——反垃圾規則會擋下這種來路不明的轉發。於是信件就卡在那裡沒送達,收件人那邊遲遲沒收到,這個「信不見了」本身就是證據。可被察覺,不代表攻擊沒發生;它只代表你事後有機會發現,而事後發現的前提,是信已經被讀過了。
他也在寄送端提了 MTA-STS。原話是 MTA-STS「can help on some specific cases, even in the absence of DNSSEC, but can easily be circumvented in many scenarios」。背景上,MTA-STS 是一種讓收信網域宣告「寄給我請強制用 TLS、認這些主機」的機制,靠 HTTPS 取得策略。Barrera 的定位很清楚:它在某些特定情境有幫助,但在許多情境可被輕易繞過——是部分緩解,不是 DNSSEC 的替代品。把它升級成「有 MTA-STS 就不必 DNSSEC」會超出他的原意。
接著是 Matrix。Barrera 說 Matrix 通訊協定採用同一套委派做法,所以以同樣方式暴露於 MITM。但他特意澄清一句,免得讀者怪錯對象:「there's nothing wrong with Matrix's approach here: it's using an industry standard approach.」問題不在 Matrix,它用的是業界標準做法;問題在忽略 DNSSEC 的服務商與本機解析器。這條歸責很重要——破綻不是某個協定設計失誤,是大家共用的解析層沒設防。
真正有趣的是 XMPP,因為它的結局不一樣。Barrera 形容 XMPP 在這件事上「really weird」,而且不以同樣方式受害。原因在憑證綁定的方向:如果他把自己的網域委派給別人的伺服器,那台伺服器需要出示的是「他自己網域」的 TLS 憑證,而不是委派目標網域的憑證。於是即使 DNS 被欺騙,最壞的結果只是 DOS,而不是 MITM——因為攻擊者那台機器拿不出你網域的憑證,連都建不起來。
這個安全性不是免費的。Barrera 指出其中古怪的一面:要把自己網域的 XMPP 委派給別人,你就得連帶把「為我的網域簽發 TLS 憑證」的能力也授權給對方。安全綁在憑證上,代價是委派時得交出簽憑證的鑰匙。把這四種情況並排,差異就一目了然。
點欄位標題可排序 · 4 列 × 4 欄
| 協定 / 路徑 | 委派靠哪種記錄 | DNS 被欺騙的最壞結果 | 為什麼是這結局 |
|---|---|---|---|
| email · client 收信 | SRV record | MITM | 連到假主機,TLS 對該主機名出示合法憑證,握手照常成立 |
| email · server 寄信 | MX record | MITM(較易留痕) | 攻擊者大概無法再轉發信件,信沒投遞會留下證據,但攻擊仍可行 |
| Matrix · 伺服器委派 | 同類委派 | MITM | 用業界標準的委派做法,協定本身無錯,問題在解析器不驗 DNSSEC |
| XMPP · 網域委派 | 委派 + 憑證綁原網域 | 僅 DOS,不 MITM | 受託伺服器須出示「原網域」憑證;攻擊者拿不出,連都建不起來 |
把信任收回本機,而不是外包給一台第三方解析器
看到這裡,一個很自然的反應是:那我把驗證交給某個會驗 DNSSEC 的公共解析器,不就好了?Barrera 直接否決了這個方向。他的判斷是,用一台第三方外部的 validating resolver「doesn't make sense」,理由有兩層。第一層,那個第三方本身就能輕易偽造回應——你只是把信任從攻擊者搬給了另一個你無法驗證的對象。第二層更致命:到那台解析器的流量本身也能被輕易攔截。
他給的類比一針見血:這就像對一台「信任的」伺服器用明文 HTTP,而它在中途把 HTTPS 剝掉。你以為自己受保護,其實保護的承諾只存在於某一段,而那段之外全裸。最後那句是整段的支點——「The whole chain is as strong as its weakest link.」整條鏈只跟最弱的那個環一樣強。
這句話值得用一個可調的圖來咀嚼。下面這個 widget 讓你拖動「到第三方解析器的路徑上經過幾個可被攔截的環節」。背景上,每多一個你不掌控的環節,就多一個攻擊者能偽造或攔截回應的位置;而整條鏈的安全等級,永遠等於最弱那一環,不會因為終點那台解析器很可信就被拉高。合理的推測是,這正是 Barrera 說「doesn't make sense」的具體模樣:你新增的信任點,並不能修復路徑上任何一個既有的弱環。
拖動滑桿增減路徑環節 · 看整條鏈停在哪一環
所以結論不是「找一台更好的解析器」,而是「別把這件事外包出去」。Barrera 給的做法很具體:他個人在每一台主機上都跑一個本機的、會做 validating 的 unbound(8) instance;他也提到 unwind(8) 是另一個漂亮的選擇。背景上,這兩個都是能在本機跑的 validating recursive resolver——驗證在你自己掌控的那台機器上發生,鏈就短到只剩你自己,路徑上沒有別人能插手的環節。
把這件事放回他開頭那個類比。HTTPS 當年面對的反對理由,今天原封不動套在 DNSSEC 上;而他真正在意的,是「almost all distributions and operating systems don't validate DNSSEC by default」——上面那些攻擊之所以對幾乎任何人都可行,純粹是因為糟糕的預設值。預設不驗,於是大多數人連自己暴露在哪都不知道。這不是一個你需要說服全世界的問題,是一個你今晚可以在自己機器上先關掉的破綻。
Take-away:TLS 證明「你連到的那台是它自稱的那台」,但證明不了「那台是你本該連的那台」——後者是 DNS 的事,沒人簽名背書時,攻擊者只要換掉一個答案,綠鎖照亮、信件照走。把驗證放回本機,別外包給任何一條你看不見的路徑。