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

當 BGP 出錯時:劫持與外洩

BGP 把整個網際網路綁在一起,靠的是相信每個網路對自己所宣稱的一切。這一段的最後一篇,要問這份信任所掀起的那個叫人不安的問題:當一個網路說了謊——無論是出於意外還是蓄意——而整個網際網路都安靜地信了它,會發生什麼事?

一個建立在信任之上的協定

在這一段裡,你看著邊界閘道協定做了一件安靜得驚人的事:靠著讓每個自治系統單純地宣告它能抵達哪些目的地、以及經由什麼樣的 AS 路徑,就把數萬個各自獨立擁有的網路縫成一個網際網路。在上一篇,你看到 BGP 是按政策與金錢、而非最短距離來挑路線的。但這一切底下藏著一個更深的假設,這篇要把它拖到光底下:BGP 相信別人告訴它的話。當一個網路宣告「我是 203.0.113.0/24 這塊位址的所在地」時,它的鄰居並沒有任何內建的辦法去查證那是不是真的。它們就只是把它記下來、再傳出去。

這並不是一時疏忽,而是源自那個年代的原始設計——當時早期網際網路上那一小撮網路是真心彼此信任的,而要替每一則宣告都加上密碼學證明,會是一個沒人覺得自己需要的沉重負擔。其結果是一個全球系統,它的正確性建立在「每個參與者都既誠實又謹慎」之上。大多數參與者確實如此。但「大多數」才是關鍵字,而「大多數」與「全部」之間的那道縫,正是出錯的地方——以下我們會逐一走過三種樣貌:路由抖動(不穩定)、劫持(一個網路宣稱不屬於自己的位址),以及外洩(一個網路把本該留在自己手裡的路線傳了出去)。

路由抖動:一條坐不住的路線

從最溫和的故障開始講,因為這裡甚至沒有人在說謊。路由抖動指的是這樣的情況:一條路線被宣告、接著又被撤回、然後又被宣告,一遍又一遍——往往是因為某處的實體鏈路或某台路由器不穩定,像個接觸不良的燈泡那樣忽明忽滅。每一次閃爍都是一則消息,而 BGP 盡職地散播消息:每一次抖動都會產生一則宣告或一則撤回,往外漣漪般傳遍整個無預設路由區,逼著遠方的路由器重算、再廣告出去。一個小網路裡的一條神經兮兮的鏈路,就能把一場更新風暴打進一片海洋之外的路由器裡。

危險的不是任何單一次抖動,而是那個倍增效應。一台被翻騰淹沒的路由器,會把時間花在重新處理路線、而不是轉送封包上,於是不穩定可能被放大、而不是平息。經典的防禦是路由抖動抑制(route flap damping):路由器盯著某個前綴抖動得有多頻繁,給它一個逐漸升高的懲罰分數,一旦分數越過門檻,就把那條路線壓制一段時間,刻意忽略關於它的後續消息,直到來源證明自己已經冷靜下來。這就是網路版的——溫和但堅定地——告訴一個慌張的朋友先去坐下,等他能講出完整的句子再說。

劫持:宣稱不屬於你的位址

現在來看那個謊言。BGP 劫持指的是一個自治系統宣告了一個它無權宣告的前綴。假設某家銀行真正擁有 198.51.100.0/24。另一個網路——出於意外或惡意——開始宣告「我也能抵達 198.51.100.0/24」。因為 BGP 信任宣告,這條路線就會傳開,而每一台後來偏好那條假路徑的路由器,都會把銀行的流量交給那個冒名頂替者。受害者甚至不見得會察覺——對那些路由器仍守著真路徑的人來說,他們自己的服務照常運作;只有被誤導的那一部分網際網路,在安靜地把流量送錯了方向。

有兩種成分讓劫持格外致命。第一種是最長前綴匹配(longest-prefix match),也就是定址那一段教過的轉送規則:路由器永遠偏好最明確的前綴。如果銀行宣告 198.51.100.0/24,而攻擊者宣告更窄的 198.51.100.0/25 與 198.51.100.128/25,那麼這些更明確的路線,會在它們所抵達的每個地方勝出,不管政策AS 路徑長度如何。第二種是攻擊者可以藉著在路徑尾端附上真正擁有者的 AS 號碼,讓路徑看起來合法,於是這條路線讀起來就像是終結在那個真正的網路。劫持已造成過真實的傷害:整個國家的流量曾被短暫地灌進錯誤的網路,有時是出於失誤,有時是為了竊聽,或是把流量吞進一個黑洞裡。

Sub-prefix hijack, why the more specific route wins

  Real owner  (AS 64500) announces:  198.51.100.0/24   path: ... 64500
  Attacker    (AS 64999) announces:  198.51.100.0/25   path: ... 64999 64500
                                     198.51.100.128/25  path: ... 64999 64500

  Router forwarding to 198.51.100.42:
    /24  matches  (covers .0  - .255)
    /25  matches  (covers .0  - .127)   <-- more specific
  longest-prefix match => pick the /25 => traffic goes to AS 64999

  Note the forged path ends in 64500, so it *looks* legitimate.
子前綴劫持會在它所抵達的每個地方擊敗真正的路線,因為最長前綴匹配完全無視 AS 路徑長度與政策,而在尾端附上真正擁有者的 AS 號碼,又把這個謊言給偽裝了起來。

外洩:把對的真話告訴錯的鄰居

路由外洩比劫持更微妙,可以說也更常見,因為沒有人宣稱自己擁有任何不屬於他的東西。外洩指的是宣告了一條為真、卻不該往那個方向傳出去的路線。回想這一段稍早講的經濟學:在供應商—客戶關係裡,你付錢給供應商,請它把你的流量載到世界其餘的地方;而對等夥伴(peer)之間,則只免費交換彼此客戶的流量。讓金錢保持理智的那條沒明說的規矩,叫做無谷規則(valley-free rule):你把客戶的路線廣告給所有人,但你絕不能把從某個供應商或對等夥伴學來的路線,再往另一個供應商或對等夥伴轉廣告出去。一旦你這麼做了,你就剛剛自願免費替他們載流量了——而更糟的是,你還告訴了整個網際網路,你是一條你根本沒能力擔當的捷徑。

外洩造成的傷害是壅塞與斷線,而非竊取。一個小型的區域網路誤把從某個大供應商聽來的路線,再轉廣告給另一個大供應商;突然之間,兩個巨頭都認為這個小網路是它們之間一條可行的轉接路徑,於是把流量灌進那些只承載得起其千分之一的鏈路裡。這個小網路熔毀了,連同所有流量被改道塞進這場堵車裡的人的連線一起熔毀。這本質上是一場自找的阻斷服務,而它不止一次讓網際網路的一大塊離線。外洩通常是誠實的失誤——一個設錯的過濾器、一個手滑打錯的政策——這正是它們如此難以根除的原因:沒有壞人可抓,只有一個漏掉的安全檢查。

補上 BGP 遺漏的查證

如果根本原因是 BGP 憑信任接受宣稱,那麼解藥全都是在加上查證宣稱的辦法。最基本也最有效的是前綴過濾(prefix filtering):供應商把自家路由器設定成,對每個客戶只接受那個客戶真正獲授權宣告的前綴,其餘一律拒絕。如果人人都認真做,這會在邊緣就擋下大多數外洩與許多劫持——麻煩在於,它仰賴每個網路都維持準確的過濾清單,而上游一個偷懶的網路,就能抵銷掉許多網路的勤勉。

更深層的修補是密碼學式的,籠統地歸在資源公鑰基礎建設(RPKI,Resource Public Key Infrastructure)底下。位址擁有者發布經簽署的紀錄——路由起源授權(ROA,Route Origin Authorisation)——載明哪個 AS 獲准起源(originate)每個前綴。路由器接著就能執行路由起源驗證(ROV),拿進來的宣告比對這些簽署紀錄,並拒絕起源 AS 對不上的那一則。這直接擊敗了最單純的劫持。不過要誠實面對它的限度:起源驗證證明的是「誰獲准宣告一個前綴」,而不是「整條 AS 路徑都是真的」,所以一個聰明、會偽造出看似合理路徑的攻擊者,仍然可能溜過去。要堵上最後那道縫,需要路徑驗證(也就是被稱為 BGPsec 的工作),那要求高得多,也幾乎還沒被部署。

  1. 位址持有者在 RPKI 裡登記一則經簽署的路由起源授權:「AS 64500 獲准起源 198.51.100.0/24。」
  2. 路由器收到一則針對 198.51.100.0/24 的 BGP 宣告,並讀取它 AS 路徑最遠端的起源 AS。
  3. 它在自己快取的、已驗證的 RPKI 紀錄裡查找這個前綴,把宣告的起源拿來和獲授權的起源比對。
  4. 若相符,這條路線就是有效的;若起源不對,它就是無效的,路由器可以丟棄它或把它降級,在這道邊界就擋下最單純的劫持。
  5. 但要注意那道縫:這只查證起源,並不查證路徑的其餘部分,所以一條偽造卻看似合理的 AS 路徑,仍可能躲過它——直到路徑驗證被廣泛部署為止。

退一步看,整段就咬合到位了。BGP 之所以是網際網路的黏著劑,正因為它寬容:任何網路都能加入、宣告自己的可達性,讓全世界繞送到它,不需要任何中央權威。那份同樣的寬容,正是它的脆弱——一個靠被廣告的路徑與相互信任綁起來的系統,所付的代價就是:單單一則造假或粗心的宣告,就能誤導整個地球。網際網路能運作,並不是因為 BGP 安全;它能運作,是因為大多數營運者在大多數時候都很謹慎,也因為我們正在慢慢地,把這個協定從未擁有的查證一件件栓上去。理解那個取捨——用脆弱換來的開放——才是域間繞送真正的一課。