DNS劫持

四火的嘮叨發表於2013-05-03

  想談一談這個話題是因為最近有一位朋友抱怨他的部落格在某些使用者某些時候訪問的時候,被莫名其妙地加上了廣告,他檢查來檢查去,始終發現不了網站本身有什麼問題,後來他才瞭解到了DNS劫持一說。

  DNS劫持

  其實這不是一個新概念了,在幾年前,中國一些不講道德的運營商,尤其是地方運營商就開始捕捉使用者瀏覽器的訪問記錄,然後根據不同使用者的訪問行為,有選擇地往使用者訪問的網頁裡面推送廣告。因為運營商掌握著DNS主機,所以他們可以為所欲為地強制改寫網站HTML頁面,採用往返回頁面裡寫入JavaScript等方式,來注入廣告:

DNS劫持

  這是訪問55BBS網站時某些使用者會在螢幕右下角看到一個京東商城的廣告。這樣的廣告,不但可以在一些中小網站上見到,在國內大型網站上也屢見不鮮。很多網民會立即懷疑自己的機器有沒有中病毒或者木馬,或者是什麼惡意的瀏覽器外掛又在作祟。其實,這都是運營商搞的鬼。

  有的使用者會堅決地投訴,運營商有自己的白名單,使用者在投訴成功以後會賬號被加入白名單,不再投放廣告。顯然他們也不想惹過多的麻煩,這樣噁心的事情需要偷偷地幹。

  另一方面,很多地方運營商會把這樣的DNS劫持後注入廣告的行為加入到使用者協議中去,讓使用者無話可說。比如北京聯通就曾經提供了不同的收費服務,一種是無廣告的,一種是包含注入廣告的,價格當然是包含廣告的更高。

  在2010年的時候,因為這樣的劫持行為,青島聯通還在一場引起軒然大波的索賠案件中敗訴,被罰20萬元給百度。索賠從金額來看顯然是小事,但是對於中國網際網路的成熟還是有積極意義的。在中國,你可以選擇的運營商就那麼幾個,就好比從一堆爛蘋果中挑選一個自己能忍受的。而且這個行業本身就缺乏道德和完善的法律約束,單單靠使用者個體抱怨和投訴,無法從根本上解決流氓行為。這也許是網際網路發展不夠成熟的一個不可迴避的陣痛。

  技術實現

  理論上說,運營商掌握了HTML頁面的全部程式碼,它可以做任何的事情,真正無縫地植入廣告,然後返還給使用者。但是,這種廣告的植入是批量的行為,如果要針對不同的網站頁面分別去設定廣告程式碼,代價未免太高了一點。另一方面,植入的JavaScript程式碼片段很容易受到不同DOM環境和JavaScript程式碼環境本身的影響,而植入廣告,不能影響到原有網站頁面的展示和行為。為了儘可能地減少植入廣告對原有網站頁面的影響,運營商通常會通過把原有網站頁面放置到一個和原頁面相同大小的iFrame裡面去,通過iFrame來隔離廣告程式碼對原有頁面的影響。由於這樣的劫持行為會針對不同使用者的某些訪問發生,我舉例不夠方便,為了讓大家能夠100%地觀察到這個效果,我找了這樣聯通的提示頁面來舉例:

  在訪問不存在的網站的時候,比如www.adfasdfasdfasdf.cn這樣亂填寫的域名,以北京聯通為例,它並不會直接返回錯誤碼,而是重定向到這樣一個錯誤提示頁面:

DNS劫持

  這個重定向後的URL為:http://bjdnserror1.wo.com.cn:8080/issueunziped/bj130404/self0.jsp?UserUrl=www.adfasdfasdfasdf.cn

  這樣的行為招來非議的人可能不多,畢竟這樣的域名確實不存在,對使用者和站長帶來的影響不大。但是,請注意它左下角和右側的廣告,在這裡它注入廣告的方式,採用的iFrame巢狀的方式,和上面我提到的劫持行為,是完全一致的。

  現在請將上述URL的self0.jsp改成index.htm,也就是:

  http://bjdnserror1.wo.com.cn:8080/issueunziped/bj130404/index.htm?UserUrl=www.adfasdfasdfasdf.cn

  你可以看到這樣的頁面:

DNS劫持

  剛才提到的廣告沒有了,對不對?

  你可以把index.htm這個頁面想象成一個網站的原始頁面,然後,運營商建立了這樣一個新頁面,而把原始頁面以iFrame的形式嵌入到其中:

<IFRAME id="fulliframe" name="fulliframe" frameSpacing=0 noResize height=1350 marginHeight=0 border=0 src="" frameBorder=0 width="100%" scrolling=no vspale="0"></IFRAME>
<script language="JavaScript" type="text/javascript">
    frames['fulliframe'].location = window.location.href.replace('self0.jsp','index.htm');
</script>

  這樣一來,就可以繼續往這個新頁面裡面寫程式碼,引入廣告了:

<script src="http://cpro.baidustatic.com/cpro/ui/f.js" type="text/javascript"></script>
<script language="JavaScript" type="text/javascript" src="bdfloat.js"></script>

  怎麼破?

  既然已經知道了原理,那麼自然就容易想到解決的辦法。對於這一類劫持,有一個共同特點是,原有網站的頁面,都是放在一個iFrame裡面的,那麼只要加上這樣的指令碼,判斷如果頁面是以一個iFrame載入的,就讓父頁面重定向到原頁面去:

if(top!==self)
    top.location.href=this.location.href;

  當然,你也可以重定向到一個你認為可靠的連結上去,甚至加上你需要的引數等等資訊(比如運營商新增的廣告程式碼URL),以記錄這一罪證。

  多說幾句

  這種劫持方式還顯得原始和粗放,而且這些採用iFrame方式實現DNS劫持的運營商還算有一些良心,因為對原有頁面的影響較小,但是還有一些地方運營商,只是往原始頁面單純地寫入javascript程式碼,很多情況下都會影響到原始頁面的展示和行為,這時候問題就顯得麻煩得多了。

  首先我們需要獲取這種行為的具體資訊,一種辦法是你掌握一個頁面原有的JavaScript方法、DOM物件列表,或者是瀏覽器請求的域名列表(類似於一個白名單),如果發現列表之外的未知方法、DOM物件的引入,或者是預期之外的URL的請求,把這樣的資訊傳送到服務端去分析。

  比如,頁面被強制注入了這樣的程式碼:

document.write("<script language='javascript' src='http://.../廣告指令碼連結'></script>");

  我們可以用一點小技巧來對付,比如JavaScript劫持:

document.write = function(){};

  讓document.write方法變成一個空函式,讓注入程式碼這一行為失效。當然,具體問題還是需要具體分析,重要的是掌握資訊。但是話說回來,我們只是程式設計師,我們創造的是原始頁面,在惡意的運營商手裡,靠技術層面的技巧,我們的力量還是太小了。

  此外,聯通的這個廣告系統做得太缺乏保護性了,只要隨便改一改連結,Tomcat版本號等等資訊就暴露出來了,如果真要有人想做點什麼的話……

DNS劫持

相關文章