低成本打造一個頻寬無限的網站 —— No.2 快取防禦攻擊
網站攻擊
有次在和朋友討論網站防護時,提到一個資訊釋出的站點 —— 它的結構很簡單,只有幾個頁面而已,正常情況下開啟是非常快的。然而一到關鍵時刻,流量如同洪水般湧來。網站無法訪問,那些付費釋出的資訊就錯過最佳展現時間了。
對於網站攻擊,現成的解決方案有很多,例如用上 WAF、CDN 等服務,多少能分擔一些。不過,通用的防禦方案,自然就有通用的攻擊方案。
例如通過 DNS 實現的負載均衡,攻擊者使用現成的工具,就能輕易遍歷出對應的 IP。更糟的是,有時域名會快取很久,使得攻擊都快結束瞭解析還沒生效。
對於前端愛好者來說,這種傳統的方案一點都不 Geek —— 理想的防護,顯然應該從前後端同時入手。
提到前端,也許你會覺得奇怪,網站都被打垮了,還哪來的前端?別急。我們先來思考個本質問題:為什麼網站容易垮。
相比網頁,傳統的應用程式在網路不好的情況下,表現的更為強勁。例如一些網路視訊播放器,即使沒連網也能啟動,只是不能觀看線上視訊而已,但仍可作為普通播放器使用;而網頁版的視訊站點,顯然就沒這麼強大了,如果沒連網,連基本介面都看不到。
這個道理大家都懂。因為應用程式是事先下載到本地的,所以後期執行時,介面、程式可以直接啟動,只有資訊才依賴網路;而網頁的介面、程式、資訊,很多時候是混在一起的,每次都得實時傳輸。所以極端情況下,網頁表現得更為脆弱。
改進
因此,我們需要對網頁做一些改造,將「介面、程式」和「資訊」徹底分離。
-
前者通常較少變動,因此可對相應的資源設定
強快取
。強快取是不走流量、直接從本地讀取的,所以使用者只要訪問過一次,之後介面就可以瞬間展現、程式可以立即執行 —— 無論網站是否繁忙! -
後者是動態載入的資料,存放位置並沒有限制,因此可放在多個後備站點上 —— 無論自己的站點,還是免費空間。
當基本介面展現後,程式通過 AJAX 從外部站點獲取資訊,然後填充到頁面裡。如果獲取失敗,則嘗試後備列表 —— 除非所有站點都垮了,否則只要有一個活著,資訊仍能展示!
有了這樣的機制,就能降低網站故障的影響了。除了沒有快取的「新使用者」無法開啟網站,那些曾經訪問過的回頭客,仍可正常瀏覽!
再改進
更進一步,只要不是服務崩潰、流量被封那種硬故障,我們還可繼續優化,使新使用者也有機會訪問。
在頻寬吃緊的情況下,我們需要對「介面和程式」進行精簡,使其只需極小的傳輸流量,從而能在夾縫中求生。
那麼,這究竟能精簡到多小?事實上,只需一行 HTML 就夠了:
<script src="//free-host-n/boot.js"></script>
我們可讓網站所有的介面和功能,都由一個外部指令碼來建立。這樣,整個站點只需一個幾十位元組的頁面,僅僅作為啟動器而已!
儘管最終 99.99% 的流量都來自其他站點,但瀏覽器的位址列,顯示的仍是當前站點:)
現在,只要頻寬還有一絲殘喘的餘地,新使用者就有機會獲取到這個迷你啟動頁,進而從網際網路上各個節點加載出完整內容!
由於整個站點只承載一個極小的檔案,因此防禦策略可以簡單很多。此外,外部指令碼的路徑可通過後端工具隨時改變,用以避開速度緩慢的節點 —— 畢竟 HTTP 控制快取的能力,比 DNS 豐富多了!
缺陷
當然,這個方案似乎過於激進 —— 不僅需要對業務做大量改造,而且對搜尋引擎也不利,因此最終並沒有實際應用。
此外,還有一個大問題也未能解決:使用者重新整理頁面,會導致強快取失效,從而產生網路請求。如果此時網站掛了,那麼使用者重新整理後,不是長時間等待,就是直接顯示錯誤。
如此美妙的防禦方案,最終卻防不住 F5 按鈕。。。這個問題,直到 HTML5 時代的一項新科技才能解決 —— 應用快取。
應用快取
關於應用快取,熟悉前端的小夥伴們都不陌生,它正是為提高 WebApp 的體驗而設計。
應用快取的用法很簡單,通過一個列表清單,告訴瀏覽器預先快取哪些資源:
<html manifest="list.appcache">
之後訪問列表中的資源時,瀏覽器就直接從本地讀取。相比強快取,應用快取的離執行緒度更高 —— 不僅沒連網也能訪問,甚至還可以重新整理!
快取不耐刷的問題,總算是能解決了。只是此時興致已過,並沒有去嘗試改進。對於瀏覽器快取,當時覺得更好玩的還是攻擊方面 —— 中間人和前端指令碼相互結合,批量汙染快取。
也許正是因為易受中間人汙染,以及 不夠靈活 等原因,應用快取始終存在一些爭議,以至於後來被 Web 標準廢棄了。取而代之的,則是一個更逆天的標準。。。