技術實踐|網易雲信 IM SDK 服務高可用技術方案

語言: CN / TW / HK

導讀:“域名劫持是網際網路攻擊的一種方式,通過攻擊域名解析伺服器(DNS),或偽造域名解析伺服器(DNS)的方法,把目標網站域名解析到錯誤的 **IP **地址從而實現使用者無法訪問目標網站的目的 或者蓄意 / 惡意要求使用者訪問指定 **IP **地址(網站)的目的 ”(以上內容引自 域名劫持 」百度百科 ) 。網易雲信 IM SDK 作為一款 ToB 產品,支撐著各種三方業務的開展。面對各種複雜的網路環境,DNS 劫持與 DNS 汙染時有發生,那麼在我們提供服務的過程中應該如何避免此類事故的發生呢?

文|郝魁

網易雲信資深 C++ 開發工程師

技術是一把雙刃劍,在大俠手中定國安邦,在鼠輩手中禍國殃民。

“域名劫持”雖然帶了“劫持”二字,但在此環境中實屬中性詞彙。例如對於一些非法網站的訪問,可以通過 DNS 服務把相應的域名解析到不可訪問的 IP 地址,以阻止對於該非法網站的訪問並給予警告等。在網易雲信即時通訊產品運維過程中,曾經發生過服務域名“netease.im”被別有用心的人或組織惡意劫持的事件,導致接入網易雲信 IM SDK 的應用無法正常登入,給客戶以及客戶的使用者造成影響。為了弄清楚這種事故是怎麼發生的,我們來分析一下網易雲信 IM SDK 的登入過程:

 

從流程上來看,在“更新 LBS”的節點上,如果發生 DNS 劫持,在訪問網易雲信 LBS 服務時有可能超時或者拿到了錯誤的應答,導致 IM SDK 無法獲取正常的 Link 伺服器地址及埠,如何避免此類事故的發生呢?本文將圍繞網易雲信端側服務高可用技術方案以及高可用元件實現方案進行具體分享。

一、如何預防 DNS 劫持

通常對於域名被劫持後,我們可以採用以下幾種方式:

 

上述幾種方式,都是在發生劫持後採取的方案,無論是從服務提供側還是服務使用側來說都不夠靈活,為了解決這些問題,提前預防事故的發生,我們主要採用以下兩種方案:

 

其中接入了 HttpDNS 服務的方案降低了所有場景下域名被劫持的風險。

1、LocalDNS域名劫持

域名劫持一直是困擾許多開發者的問題之一,其表現為域名 A 應該返回的 DNS 解析結果 IP1 被惡意替換為了 IP2,導致 A 的訪問失敗或訪問了一個不安全的站點,常見域名劫持方式有以下幾種:

  • 黑客入侵寬頻路由器,篡改終端使用者 LocalDNS,並指向偽造 LocalDNS,通過控制 LocalDNS 的邏輯返回錯誤的 IP 資訊進行域名劫持。

  • 監聽終端使用者域名解析請求,在 LocalDNS 返回正確結果之前將偽造的 DNS 解析響應傳遞給終端使用者,進而控制終端使用者的域名訪問行為。

  • 快取汙染,LocalDNS 快取了域名的解析結果,並對部分域名結果進行更改,導致使用者訪問被指向被更改的地址,示意圖如下:

 

 

2、HttpDNS實現原理

S tep1 客戶端直接訪問 HttpDNS 介面,獲取業務在域名配置管理系統上配置的“正確的”、“訪問速度最優的” IP列表。

S tep2 客戶端向獲取到的 IP 後就向直接往此 IP 傳送業務協議請求。以 HTTP 請求為例,通過在 header 中指定 Host 欄位,向 HttpDNS 返回的 IP 傳送標準的 Http 請求即可,如果是 Https 還要考慮 SNI 的問題。

 

 

二、網易雲信服務高可用策略

為了提高服務的高可用性,網易雲信 SDK 接入了 HttpDNS 服務,高可用方案整體結構如下所示:

 

IM SDK 接入 HttpDNS 服務實現服務高可用的一般流程:

 

 

1、端側 HttpDNS SDK 實現

IM SDK 高可用元件採用了跨平臺開發方案,主要針對 Native SDK(Windows、MacOS、iOS、Android)進行了支援,基本結構如下:

 

高可用元件為了保證高可用性、響應的及時性、結果的正確性,在設計時需要完成以下幾個功能:

  • HttpDNS 服務介面的更新及快取維護

  • 域名查詢結果更新及快取維護

  • HTTP 請求的實現

1.1 階梯式 HTTP 請求

某一域名通過 HttpDNS 的域名查詢服務,可能會解析出多個 IP 地址,如果這些地址當中包含已下線或者訪問速度不理想的節點,會使整個 HTTP 的訪問時間變長,最壞的情況是所有的地址都進行了訪問,且都超時,如下圖所示:

 

 

 

為了提高 HTTP 請求的訪問效率,在網易雲信高可用元件中引入了多地址階梯式的 HTTP 請求機制,比如單一連結的 HTTP 請求超時時間指定為 30s,當開始第一個連結訪問時開啟一個超時時間為 3 秒的定時器 Timer0,如果該請求在 3 秒內返回並且經過業務模組驗證為正確應答,此時整個多地址階梯式請求結束,否則在 Timer0 觸發時,啟動對下一連結的 HTTP 請求,並啟動一個新的超時時間為 3 秒的定時器 Time1,以此類推,直到有正確的響應結果或者所有的連結都已訪問完成,流程如下所示:

 

 

 

 

1.2 HttpDNS 服務介面的更新及快取維護

HttpDNS 也是一個 HTTP 服務也存在被劫持的可能,所以除了使用 HttpDNS 域名外,高可用元件還內建了多個固化的 IP,以解決 HttpDNS 域名被劫持後無法訪問的問題,使用固化 IP 雖然可以解決域名被劫持的問題,但不一定是最新、最優的節點,為了解決這個問題,高可用元件在指定時間內會更新 HttpDNS服務地址,拿到最新、最優的節點。為了減少對 HttpDNS的訪問量,引入了服務地址的 TTL(一般是1小時)機制,即在服務地址有效期內使用本地快取,不再向 HttpDNS 請求服務地址。

HttpDNS 服務初始化流程如下:

 

1.3 域名查詢結果更新及快取維護

高可用元件為了保證域名查詢的及時響應,以及減少對 HttpDNS 的訪問量,引入了“查詢結果快取”,對已經查詢過的域名結果進行了本地快取,為了提高正確性同樣也加入了 TTL 機制(一般是 5 分鐘),超出指定時間後,會對結果進行再次更新,同時為了保證響應的及時性,在 TTL 的基礎上加入了冗餘時間(一般是 TTL*0.75),所以呼叫高可用元件查詢域名會存在三種結果:

  • 快取未到達冗餘時間,返回快取結果。

  • 快取達到冗餘時間,但尚未過期,返回快取結果,同時發起更新請求。

  • 快取已過期,發起更新請求,應答成功後,更新快取,響應上層呼叫,如果應答失敗,繼續使用快取資料。

呼叫高可用元件進行域名查詢的流程如下:

 

 

1.4 HTTP 訪問流程設計

 

 

2、疑似劫持事件上報

當呼叫高可用元件進行 HTTP 請求時,如果因非網路原因導致的請求失敗,而且觸發了 HttpDNS 查詢域名操作,則判定此次訪問的域名可能存在已被劫持的風險,高可用元件會收集與此域名相關的資訊內容上報到網易雲信資料大盤,資料大盤後臺根據上報資訊來定位是否存在域名劫持的情況,並根據實際情況來決定是否要重新配置 HttpDNS 解析結果還是配合安全部門對相應的 App 進行封禁處理。

 

3、SNI 處理

為了讓多個域名複用一個 IP,在 HTTP 伺服器上引入了虛擬主機的概念。多個虛擬主機共享 IP 的 HTTPS 伺服器中,在握手建立之前伺服器無法知道客戶端請求的具體 Host,所以無法將請求交給特定的虛擬主機,從而導致伺服器無法讀取虛擬主機中配置的證書資訊。SNI 就是用來解決這個問題的,SNI 是 SSL 和 TLS 的一個擴充套件協議。SNI 要求客戶端在與伺服器握手時就攜帶需要訪問的域名的 Host 資訊,具體實現方法是在客戶端“Client Hello”報文的請求頭中,增加了 Server Name 的擴充套件欄位,因此伺服器便會知道需要用哪個虛擬主機的證書與客戶端握手並建立 TLS 連線。

以下是使用 libcurl 傳送 HTTP 請求的程式碼片段:

 

 

DNS汙染_百度百科 (baidu.com)

域名劫持_百度百科 (baidu.com)

域名伺服器快取汙染 - 維基百科,自由的百科全書 (wikipedia.org)

以上就是網易雲信端側服務高可用技術方案以及高可用元件實現方案的分享,如有興趣,歡迎你在公眾號留言與我探討。

作者介紹

郝魁,網易雲信資深 C++ 開發工程師,主要負責網易雲信 IM SDK 的開發、維護、重構等工作,擁有多年 C++ 客戶端開發經驗,現致力於跨平臺 C++ 開發。