39 | 案例篇:怎么缓解 DDoS 攻击带来的性能下降问题?
生活随笔
收集整理的這篇文章主要介紹了
39 | 案例篇:怎么缓解 DDoS 攻击带来的性能下降问题?
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
上一節,學習了 tcpdump 和 Wireshark 的使用方法,并通過幾個案例,帶你用這兩個工具實際分析了網絡的收發過程。碰到網絡性能問題,不要忘記可以用 tcpdump 和 Wireshark 這兩個大殺器,抓取實際傳輸的網絡包,排查潛在的性能問題。今天,來看另外一個問題,怎么緩解 DDoS(Distributed Denial of Service)帶來的性能下降問題。
DDoS 簡介
DDoS 的前身是 DoS(Denail of Service),即拒絕服務攻擊,指利用大量的合理請求,來占用過多的目標資源,從而使目標服務無法響應正常請求。DDoS(Distributed Denial of Service) 則是在 DoS 的基礎上,采用了分布式架構,利用多臺主機同時攻擊目標主機。這樣,即使目標服務部署了網絡防御設備,面對大量網絡請求時,還是無力應對。比如,目前已知的最大流量攻擊,正是去年 Github 遭受的 DDoS 攻擊,其峰值流量已經達到了 1.35Tbps,PPS 更是超過了 1.2 億(126.9 million)。從攻擊的原理上來看,DDoS 可以分為下面幾種類型。- 第一種,耗盡帶寬。無論是服務器還是路由器、交換機等網絡設備,帶寬都有固定的上限。帶寬耗盡后,就會發生網絡擁堵,從而無法傳輸其他正常的網絡報文。
- 第二種,耗盡操作系統的資源。網絡服務的正常運行,都需要一定的系統資源,像是 CPU、內存等物理資源,以及連接表等軟件資源。一旦資源耗盡,系統就不能處理其他正常的網絡連接。
- 第三種,消耗應用程序的運行資源。應用程序的運行,通常還需要跟其他的資源或系統交互。如果應用程序一直忙于處理無效請求,也會導致正常請求的處理變慢,甚至得不到響應。
案例準備
下面的案例仍然基于 Ubuntu 18.04,同樣適用于其他的 Linux 系統。我使用的案例環境是這樣的:機器配置:2 CPU,8GB 內存。預先安裝 docker、sar 、hping3、tcpdump、curl 等工具,比如 apt-get install docker.io hping3 tcpdump curl這些工具你應該都比較熟悉了。其中,hping3 在 系統的軟中斷 CPU 使用率升高案例 中曾經介紹過,它可以構造 TCP/IP 協議數據包,對系統進行安全審計、防火墻測試、DoS 攻擊測試等。本次案例用到三臺虛擬機,我畫了一張圖來表示它們之間的關系。你可以看到,其中一臺虛擬機運行 Nginx ,用來模擬待分析的 Web 服務器;而另外兩臺作為 Web 服務器的客戶端,其中一臺用作 DoS 攻擊,而另一臺則是正常的客戶端。使用多臺虛擬機的目的,自然還是為了相互隔離,避免“交叉感染”。由于案例只使用了一臺機器作為攻擊源,所以這里的攻擊,實際上還是傳統的 DoS ,而非 DDoS。接下來,我們打開三個終端,分別 SSH 登錄到三臺機器上(下面的步驟,都假設終端編號與圖示 VM 編號一致),并安裝上面提到的這些工具。同以前的案例一樣,下面的所有命令,都默認以 root 用戶運行。如果你是用普通用戶身份登陸系統,請運行 sudo su root 命令切換到 root 用戶。接下來,我們就進入到案例操作環節。案例分析
首先,在終端一中,執行下面的命令運行案例,也就是啟動一個最基本的 Nginx 應用:# 運行 Nginx 服務并對外開放 80 端口 # --network=host 表示使用主機網絡(這是為了方便后面排查問題) $ docker run -itd --name=nginx --network=host nginx然后,在終端二和終端三中,使用 curl 訪問 Nginx 監聽的端口,確認 Nginx 正常啟動。假設 192.168.0.30 是 Nginx 所在虛擬機的 IP 地址,那么運行 curl 命令后,你應該會看到下面這個輸出界面:# -w 表示只輸出 HTTP 狀態碼及總時間,-o 表示將響應重定向到 /dev/null $ curl -s -w 'Http code: %{http_code}\nTotal time:%{time_total}s\n' -o /dev/null http://192.168.0.30/ ... Http code: 200 Total time:0.002s從這里可以看到,正常情況下,我們訪問 Nginx 只需要 2ms(0.002s)。接著,在終端二中,運行 hping3 命令,來模擬 DoS 攻擊:# -S 參數表示設置 TCP 協議的 SYN(同步序列號),-p 表示目的端口為 80 # -i u10 表示每隔 10 微秒發送一個網絡幀 $ hping3 -S -p 80 -i u10 192.168.0.30現在,再回到終端一,你就會發現,現在不管執行什么命令,都慢了很多。不過,在實踐時要注意:- 如果你的現象不那么明顯,那么請嘗試把參數里面的 u10 調小(比如調成 u1),或者加上–flood 選項;
- 如果你的終端一完全沒有響應了,那么請適當調大 u10(比如調成 u30),否則后面就不能通過 SSH 操作 VM1。
- 即客戶端構造大量的 SYN 包,請求建立 TCP 連接;
- 而服務器收到包后,會向源 IP 發送 SYN+ACK 報文,并等待三次握手的最后一次 ACK 報文,直到超時。
攻擊源IP不固定解決的方法
不過,一般來說,SYN Flood 攻擊中的源 IP 并不是固定的。比如,你可以在 hping3 命令中,加入 --rand-source 選項,來隨機化源 IP。不過,這時,剛才的方法就不適用了。幸好,我們還有很多其他方法,實現類似的目標。比如,你可以用以下兩種方法,來限制 syn 包的速率:# 限制 syn 并發數為每秒 1 次 $ iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT# 限制單個 IP 在 60 秒新建立的連接數為 10 $ iptables -I INPUT -p tcp --dport 80 --syn -m recent --name SYN_FLOOD --update --seconds 60 --hitcount 10 -j REJECT到這里,我們已經初步限制了 SYN Flood 攻擊。不過這還不夠,因為我們的案例還只是單個的攻擊源。如果是多臺機器同時發送 SYN Flood,這種方法可能就直接無效了。因為你很可能無法 SSH 登錄(SSH 也是基于 TCP 的)到機器上去,更別提執行上述所有的排查命令。系統 TCP 優化
所以,這還需要你事先對系統做一些 TCP 優化。比如,SYN Flood 會導致 SYN_RECV 狀態的連接急劇增大。在上面的 netstat 命令中,你也可以看到 190 多個處于半開狀態的連接。不過,半開狀態的連接數是有限制的,執行下面的命令,你就可以看到,默認的半連接容量只有 256:$ sysctl net.ipv4.tcp_max_syn_backlog net.ipv4.tcp_max_syn_backlog = 256換句話說, SYN 包數再稍微增大一些,就不能 SSH 登錄機器了。 所以,你還應該增大半連接的容量,比如,你可以用下面的命令,將其增大為 1024:$ sysctl -w net.ipv4.tcp_max_syn_backlog=1024 net.ipv4.tcp_max_syn_backlog = 1024另外,連接每個 SYN_RECV 時,如果失敗的話,內核還會自動重試,并且默認的重試次數是 5 次。你可以執行下面的命令,將其減小為 1 次:$ sysctl -w net.ipv4.tcp_synack_retries=1 net.ipv4.tcp_synack_retries = 1開啟 SYN Cookies
除此之外,TCP SYN Cookies 也是一種專門防御 SYN Flood 攻擊的方法。SYN Cookies 基于連接信息(包括源地址、源端口、目的地址、目的端口等)以及一個加密種子(如系統啟動時間),計算出一個哈希值(SHA1),這個哈希值稱為 cookie。然后,這個 cookie 就被用作序列號,來應答 SYN+ACK 包,并釋放連接狀態。當客戶端發送完三次握手的最后一次 ACK 后,服務器就會再次計算這個哈希值,確認是上次返回的 SYN+ACK 的返回包,才會進入 TCP 的連接狀態。因而,開啟 SYN Cookies 后,就不需要維護半開連接狀態了,進而也就沒有了半連接數的限制。注意,開啟 TCP syncookies 后,內核選項 net.ipv4.tcp_max_syn_backlog 也就無效了。你可以通過下面的命令,開啟 TCP SYN Cookies:$ sysctl -w net.ipv4.tcp_syncookies=1 net.ipv4.tcp_syncookies = 1注意,上述 sysctl 命令修改的配置都是臨時的,重啟后這些配置就會丟失。所以,為了保證配置持久化,你還應該把這些配置,寫入 /etc/sysctl.conf 文件中。比如:$ cat /etc/sysctl.conf net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_synack_retries = 1 net.ipv4.tcp_max_syn_backlog = 1024不過要記得,寫入 /etc/sysctl.conf 的配置,需要執行 sysctl -p 命令后,才會動態生效。當然案例結束后,別忘了執行 docker rm -f nginx 命令,清理案例開始時啟動的 Nginx 應用。DDoS 到底該怎么防御
到這里,今天的案例就結束了。不過,你肯定還有疑問。你應該注意到了,今天的主題是“緩解”,而不是“解決” DDoS 問題。為什么不是解決 DDoS ,而只是緩解呢?而且今天案例中的方法,也只是讓 Nginx 服務訪問不再超時,但訪問延遲還是比一開始時的 2ms 大得多。內核參數
實際上,當 DDoS 報文到達服務器后,Linux 提供的機制只能緩解,而無法徹底解決。即使像是 SYN Flood 這樣的小包攻擊,其巨大的 PPS ,也會導致 Linux 內核消耗大量資源,進而導致其他網絡報文的處理緩慢。雖然你可以調整內核參數,緩解 DDoS 帶來的性能問題,卻也會像案例這樣,無法徹底解決它。跳過內核協議棧
在之前的 C10K、C100K 文章 中,我也提到過,Linux 內核中冗長的協議棧,在 PPS 很大時,就是一個巨大的負擔。對 DDoS 攻擊來說,也是一樣的道理。所以,當時提到的 C10M 的方法,用到這里同樣適合。比如,你可以基于 XDP 或者 DPDK,構建 DDoS 方案,在內核網絡協議棧前,或者跳過內核協議棧,來識別并丟棄 DDoS 報文,避免 DDoS 對系統其他資源的消耗。阻斷流量
不過,對于流量型的 DDoS 來說,當服務器的帶寬被耗盡后,在服務器內部處理就無能為力了。這時,只能在服務器外部的網絡設備中,設法識別并阻斷流量(當然前提是網絡設備要能扛住流量攻擊)。比如,購置專業的入侵檢測和防御設備,配置流量清洗設備阻斷惡意流量等。既然 DDoS 這么難防御,這是不是說明, Linux 服務器內部壓根兒就不關注這一點,而是全部交給專業的網絡設備來處理呢?應用層面
當然不是,因為 DDoS 并不一定是因為大流量或者大 PPS,有時候,慢速的請求也會帶來巨大的性能下降(這種情況稱為慢速 DDoS)。比如,很多針對應用程序的攻擊,都會偽裝成正常用戶來請求資源。這種情況下,請求流量可能本身并不大,但響應流量卻可能很大,并且應用程序內部也很可能要耗費大量資源處理。這時,就需要應用程序考慮識別,并盡早拒絕掉這些惡意流量,比如合理利用緩存、增加 WAF(Web Application Firewall)、使用 CDN 等等。小結
今天,我們學習了分布式拒絕服務(DDoS)時的緩解方法。DDoS 利用大量的偽造請求,使目標服務耗費大量資源,來處理這些無效請求,進而無法正常響應正常的用戶請求。由于 DDoS 的分布式、大流量、難追蹤等特點,目前還沒有方法可以完全防御 DDoS 帶來的問題,只能設法緩解這個影響。比如,你可以購買專業的流量清洗設備和網絡防火墻,在網絡入口處阻斷惡意流量,只保留正常流量進入數據中心的服務器中。在 Linux 服務器中,你可以通過內核調優、DPDK、XDP 等多種方法,來增大服務器的抗攻擊能力,降低 DDoS 對正常服務的影響。而在應用程序中,你可以利用各級緩存、 WAF、CDN 等方式,緩解 DDoS 對應用程序的影響。思考最后給你留一個思考題。看到今天的案例,你可能會覺得眼熟。實際上,它正是在 系統的軟中斷 CPU 使用率升高案例 基礎上擴展而來的。當時,我們是從軟中斷 CPU 使用率的角度來分析的,也就是說,DDoS 會導致軟中斷 CPU 使用率(softirq)升高。回想一下當時的案例和分析思路,再結合今天的案例,你覺得還有沒有更好的方法,來檢測 DDoS 攻擊呢?除了 tcpdump,還有哪些方法查找這些攻擊的源地址?1 增大隊列SYN最大半連接數 sysctl -w et.ipv4.tcp_max_syn_backlog=30002 減少超時值:通過減少超時重傳次數,sysctl -w net.ipv4.tcp_synack_retries=13 SYN_COOKIE : 開啟cookie echo "1" > / proc/sys/net/ipv4/tcp_syncookies?4 過濾可疑IP地址: iptables -I INPUT -s 192.168.0.2 -p tcp -j REJECT 禁止 0.2訪問阿里云的高防總結
以上是生活随笔為你收集整理的39 | 案例篇:怎么缓解 DDoS 攻击带来的性能下降问题?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 38 | 案例篇:怎么使用 tcpdum
- 下一篇: 40 | 案例篇:网络请求延迟变大了,我