JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

保護 DNS:DNSSEC 與加密查詢

這本把名字翻成位址的電話簿,誕生於一個更信任彼此的年代——預設情況下,它既不證明「是誰回答的」,也不隱藏「你問了什麼」。本篇介紹兩個各自獨立的修補:一個替答案簽名,一個把問題藏起來。

一本從不查證來源的電話簿

你現在已經知道 網域名稱系統如何把 example.com 這樣的名字翻成位址:你的解析器從根往下走到 頂層網域、再到權威伺服器,沿途蒐集資源記錄,並把每個答案快取到它的 TTL 允許的期限為止。這是一場規模的奇蹟。但請注意前幾篇悄悄沒提到的事:從頭到尾,沒有任何人證明過那個答案是真的,也從頭到尾,沒有人把那個問題對「監看線路的人」藏起來。

這不是某人忘了修的臭蟲——而是 DNS 誕生的那個年代使然。在早期的網際網路上,連在上面的機器大致彼此信任,而一次樸實、快速、未加密的查詢,正是當時想要的。所以 DNS 預設既是未經驗證的(它不證明究竟是誰回答的),也是未加密的(路徑上任何人都能讀到你的查詢)。這是兩個不同的弱點,需要兩個不同的修補。把它們分開來看,正是本篇的重點所在。

把傳統的 DNS 答案想成一張明信片,由一個陌生人遞給你並說:「這就是你要的位址。」有兩個問題該讓你不安。第一:這個陌生人真的是從那個名字的正當擁有者那裡拿到位址的嗎,還是自己捏造的?第二:在這張明信片送到我手上的路上,還有誰讀過它,他們看見了我在問哪個名字嗎?第一個是「完整性與來源」的問題;第二個是「隱私」的問題。我們會照這個順序逐一處理。

讓這件事變嚴重的攻擊:快取下毒

為什麼要在意「答案未經驗證」?因為快取——這個讓 DNS 變快的東西——同時也讓一個偽造的答案變得危險。傳統的 DNS 查詢以一則沒有保護的單一訊息經 UDP 送出,而解析器只是單純信任「第一則欄位對得上」的回覆。能猜中或觀察到那些欄位的攻擊者,就能搶著先送出一則假回覆——一筆偽造的記錄,宣稱 example.com 住在攻擊者的位址。這就是 偽冒,而當這份下了毒的答案落進解析器的快取裡,這台解析器後面的每一位使用者,都會被悄悄送往錯誤的地方,直到 TTL 過期為止。

損害會層層放大,因為錯誤的位址可以把你帶到任何地方。被送到攻擊者的伺服器後,你可能交出一個密碼,或下載某個惡意的東西,而這一切發生時,你網址列裡的名字看起來都還是 example.com。請精確地看清這道信任的缺口:危險不在於有人讀了你的查詢——而在於你無法分辨一個真答案與一個偽造答案。再多的速度或快取都修不了這件事。缺的,是一個讓名字的正當擁有者能在自己記錄上蓋下「動過就看得出來」封印的方法,好讓解析器拒絕任何被竄改或偽造的東西。那個封印,就是 DNSSEC。

DNSSEC:替答案簽名

DNSSEC(DNS 安全擴充)對付的是第一個問題——真實性——而且只對付這一個。它的工具,是你在安全那一級見過的數位簽章。一個區域(zone)的擁有者握有一把私鑰,用它替每一組記錄簽名;對應的公鑰則公布在這個區域本身裡。當解析器去取 example.com 的位址時,它也一併取得一個簽章,並用公鑰去驗證那個簽章。只要記錄在傳輸途中有一個位元組被動過,數學就對不上,解析器就把這個答案丟掉。封印破了,答案就被拒絕。

但一個簽章的價值,頂多等於你對「製造它的那把鑰匙」的信任。你怎麼知道 example.com 的公鑰本身是真的、而不是也被偽造的?DNSSEC 用一條信任鏈來回答這個問題,而這條鏈正好對映你早已熟悉的 DNS 階層。根區域為每個 TLD 的金鑰背書,每個 TLD 為其下各區域的金鑰背書,如此一路往下到 example.com。每一層都替子層金鑰的一小段指紋簽名,於是信任一環扣一環地往下流。你只需要信任最頂端的那一樣東西——根的金鑰,那個著名的信任錨點——其下的一切,都能從那裡開始驗證。

  1. 你的解析器向根詢問 example.com 的信任鏈,取得根所簽署、指向 .com 區域金鑰的指標——一段它能拿來和手上既有的信任錨點核對的指紋。
  2. 如今已被信任的 .com 區域,交出一個指向 example.com 金鑰、且已簽署的指標。每一環都先驗證、才走下一環,所以任何地方出現偽造金鑰,都會弄斷這條鏈。
  3. 最後,example.com 替真正的位址記錄簽名。解析器用如今已被信任的金鑰去驗證那個簽章,唯有簽章成立,才接受這個位址。

加密查詢:把問題藏起來

現在來看第二個弱點。即使有 DNSSEC 把每個答案都封了印,傳統查詢依然以明文傳送,所以你的網路供應商、一家咖啡店的 Wi-Fi 業者,或任何在線路上竊聽的人,都能讀到一份你查詢過的每一個網站的連續清單——一本意外洩底的日記,甚至在你還沒載入任何一個頁面之前就已如此。修補之道,是把整段對話裹進加密裡,而工具是你早已見過的那個:TLS,正是替 HTTPS 掛上那把鎖的同一份保護。

要做到這件事,有兩種標準做法。DNS over HTTPS(DoH)把你的查詢塞進普通的 HTTPS 請求裡,所以在監看者眼中,它們看起來就和一般網頁流量一模一樣,融進人群中。DNS over TLS(DoT)做同樣的加密,但走自己專屬的連接埠,這讓網路業者比較容易把它看成、並當成 DNS 來管理——即使他們依然讀不到裡頭的內容。兩者都騎在 TLS 上;差別主要在於流量有多顯眼、以及由誰來掌控它。無論哪一種,竊聽者如今看見的,都只是一條通往你所選解析器的加密通道。

兩個修補、一張圖,以及誠實的限制

把這一切記牢的最乾淨方式,是記住「完整性」與「隱私」是兩條彼此獨立的軸,而一次受到完整保護的查詢,兩者都想要。DNSSEC 替答案簽名,讓你能信任它是真的;加密 DNS 把問題裹起來,讓別人讀不到。你可以只有其中一個而沒有另一個,而歷史上網際網路的大部分時候,兩個都沒有。下面這張小表,把「誰解決什麼」攤開來。

                      | proves answer is | hides the
                      | genuine?         | question?
  --------------------+------------------+-----------
  plain DNS (default) |       no         |    no
  DNSSEC              |      YES         |    no
  DNS over HTTPS/TLS  |       no         |   YES
  DNSSEC + encrypted  |      YES         |   YES
兩個彼此獨立的問題,兩個彼此獨立的修補。DNSSEC 管的是真實性(動過就看得出來的封印);加密 DNS 管的是隱私(密封的信封)。完整的保護兩者都要,因為兩者誰也做不了對方的工作。

幾個誠實的提醒,能讓這一切不致變成魔法棒。DNSSEC 的採用是真實存在的,但遠談不上普及——許多區域至今仍完全不公布任何簽章,所以解析器根本沒有東西可驗證,只能退回去信任那個明文答案。這條鏈也仰賴註冊商與區域業者把金鑰正確設定好,而一次搞砸的金鑰輪替,可能讓整個網域下線。同時,即使是一個安全解析出來的位址,也只是告訴你的瀏覽器「該連到哪裡」;要證明你真的在和正確的伺服器對話、並把頁面本身加密,那仍然是上一層的 TLS 與它的憑證的工作。保護名字,是第一步,而不是終點線。

這就為 DNS 這一級畫上句點。你從「我們究竟為什麼需要名字」這個問題出發,攀爬了從根到權威伺服器的階層,一步步追蹤了一次查詢,學會了記錄與 TTL 如何讓快取把整套系統擴展開來,如今又看見了如何替答案封印、把問題藏起。同樣這套「兩條軸」的思考——這是真的嗎、這是隱密的嗎——會一路跟著你爬完這座梯子的其餘部分,進入 TLS、進入 QUIC 的設計,並進入網際網路每一個「不得不把信任,事後補裝到一個當初並未為它而建的系統上」的地方。