從 2023 年 8 月 25 日開始,我們開始注意到一些異常嚴(yán)重的 HTTP 攻擊攻擊了很多我們的用戶。 幸運(yùn)的是我們的自動(dòng)化 DDoS 系統(tǒng)檢測(cè)到并緩解了這些攻擊。 然而,沒過多久,它們的規(guī)模就開始達(dá)到破紀(jì)錄的水平,并最終達(dá)到每秒略高于 2.01 億個(gè)請(qǐng)求的峰值。 這相當(dāng)于我們之前有記錄以來最大攻擊規(guī)模的三倍。而更令人擔(dān)憂的是,攻擊者能夠利用僅由 20,000 臺(tái)機(jī)器組成的僵尸網(wǎng)絡(luò)發(fā)起此類攻擊。 而如今的僵尸網(wǎng)絡(luò)規(guī)??蛇_(dá)數(shù)十萬(wàn)或數(shù)百萬(wàn)臺(tái)機(jī)器。 整個(gè)web網(wǎng)絡(luò)通常每秒處理 10-30 億個(gè)請(qǐng)求,因此使用此方法可以將整個(gè)web網(wǎng)絡(luò)的請(qǐng)求數(shù)量等級(jí)集中在少數(shù)目標(biāo)上,而這并非不可想象。
如果您正在遭受類似攻擊或想尋求增強(qiáng)安全防護(hù)支持
檢測(cè)和緩解情況概述
這是一種規(guī)??涨暗男滦凸羰侄危珻loudflare 現(xiàn)有的保護(hù)措施在很大程度上能夠抵御這種攻擊的沖擊。 雖然最初我們看到了對(duì)客戶流量的一些影響(在第一波攻擊期間影響了大約 1% 的請(qǐng)求),但今天我們已經(jīng)能夠改進(jìn)我們的緩解方法,以阻止任何 針對(duì)Cloudflare 客戶的攻擊,也不影響我們自身的系統(tǒng)正常運(yùn)行。
我們注意到這些攻擊的同時(shí),另外兩個(gè)主要行業(yè)參與者——谷歌和 AWS——也看到了同樣的情況。 我們致力于強(qiáng)化 Cloudflare 的系統(tǒng),以確保今天我們的所有客戶都能免受這種新的 DDoS 攻擊方法的影響,而不會(huì)對(duì)客戶造成任何影響。 我們還與 Google 和 AWS 合作,向受影響的供應(yīng)商和關(guān)鍵基礎(chǔ)設(shè)施提供商協(xié)調(diào)披露此次攻擊。
這種攻擊是通過濫用 HTTP/2 協(xié)議的某些功能和服務(wù)器實(shí)現(xiàn)細(xì)節(jié)而實(shí)現(xiàn)的。 由于該攻擊利用了 HTTP/2 協(xié)議中的潛在弱點(diǎn),因此我們相信任何實(shí)施了 HTTP/2 的供應(yīng)商都將受到攻擊。 這包括所有現(xiàn)代網(wǎng)絡(luò)服務(wù)器。 我們與 Google 和 AWS 一起向 Web 服務(wù)器供應(yīng)商披露了攻擊方法,我們預(yù)計(jì)他們將實(shí)施補(bǔ)丁。 與此同時(shí),最好的防御措施是在任何 Web 或 API 服務(wù)器前面使用 Cloudflare 等 DDoS 緩解服務(wù)。
這篇文章深入探討了 HTTP/2 協(xié)議的詳細(xì)信息、攻擊者用來生成這些大規(guī)模攻擊的方法,以及我們?yōu)榇_保所有客戶受到保護(hù)而采取的緩解策略。 我們希望通過發(fā)布這些詳細(xì)信息,其他受影響的網(wǎng)絡(luò)服務(wù)器和服務(wù)將獲得實(shí)施緩解策略所需的信息。 此外,HTTP/2 協(xié)議標(biāo)準(zhǔn)團(tuán)隊(duì)以及致力于未來 Web 標(biāo)準(zhǔn)的團(tuán)隊(duì)可以更好地設(shè)計(jì)它們以防止此類攻擊。
RST攻擊細(xì)節(jié)
HTTP 是為 Web 提供支持的應(yīng)用程序協(xié)議。 HTTP 語(yǔ)義對(duì)于所有版本的 HTTP 都是通用的 — 整體架構(gòu)、術(shù)語(yǔ)和協(xié)議方面,例如請(qǐng)求和響應(yīng)消息、方法、狀態(tài)代碼、標(biāo)頭和尾部字段、消息內(nèi)容等等。 每個(gè)單獨(dú)的 HTTP 版本都定義了如何將語(yǔ)義轉(zhuǎn)換為“有線格式”以通過 Internet 進(jìn)行交換。 例如,客戶端必須將請(qǐng)求消息序列化為二進(jìn)制數(shù)據(jù)并發(fā)送,然后服務(wù)器將其解析回它可以處理的消息。
HTTP/1.1 使用文本形式的序列化。 請(qǐng)求和響應(yīng)消息作為 ASCII 字符流進(jìn)行交換,通過可靠的傳輸層(如 TCP)發(fā)送,使用以下格式(其中 CRLF 表示回車和換行):
HTTP-message = start-line CRLF
( field-line CRLF )
CRLF
【 message-body 】
例如,對(duì)于 https://blog.cloudflare.com/ 的一個(gè)非常簡(jiǎn)單的 GET 請(qǐng)求在線路上將如下所示:
GET / HTTP/1.1 CRLFhost:blog.cloudflare.comCRLF
響應(yīng)將如下所示:
HTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLF<100 bytes of data>
這種格式在線路上構(gòu)造消息,這意味著可以使用單個(gè) TCP 連接來交換多個(gè)請(qǐng)求和響應(yīng)。 但是,該格式要求每條消息都完整發(fā)送。 此外,為了正確地將請(qǐng)求與響應(yīng)關(guān)聯(lián)起來,需要嚴(yán)格的排序; 這意味著消息是串行交換的并且不能多路復(fù)用。 https://blog.cloudflare.com/ 和 https://blog.cloudflare.com/page/2/ 的兩個(gè) GET 請(qǐng)求將是:
GET / HTTP/1.1 CRLFHost: blog.cloudflare.comCRLFGET /page/2 HTTP/1.1 CRLFHost: blog.cloudflare.comCRLF
而response是:
HTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLF<100 bytes of data>HTTP/1.1 200 OK CRLFServer: cloudflareCRLFContent-Length: 100CRLFtext/html; charset=UTF-8CRLF<100 bytes of data>
網(wǎng)頁(yè)需要比這些示例更復(fù)雜的 HTTP 交互。 訪問 Cloudflare 博客時(shí),您的瀏覽器將加載多個(gè)腳本、樣式和媒體資產(chǎn)。 如果您使用 HTTP/1.1 訪問首頁(yè)并決定快速導(dǎo)航到第 2 頁(yè),您的瀏覽器可以從兩個(gè)選項(xiàng)中進(jìn)行選擇。 在第 2 頁(yè)甚至可以啟動(dòng)之前,等待您不再需要的頁(yè)面的所有排隊(duì)響應(yīng),或者通過關(guān)閉 TCP 連接并打開新連接來取消正在進(jìn)行的請(qǐng)求。 這些都不太實(shí)用。 瀏覽器傾向于通過管理 TCP 連接池(每個(gè)主機(jī)最多 6 個(gè))并在池上實(shí)現(xiàn)復(fù)雜的請(qǐng)求分派邏輯來解決這些限制。
HTTP/2 解決了 HTTP/1.1 的許多問題。 每個(gè) HTTP 消息都被序列化為一組 HTTP/2 幀,這些幀具有類型、長(zhǎng)度、標(biāo)志、流標(biāo)識(shí)符 (ID) 和有效負(fù)載。 流 ID 清楚地表明線路上的哪些字節(jié)適用于哪個(gè)消息,從而允許安全的多路復(fù)用和并發(fā)。 流是雙向的。 客戶端發(fā)送幀,服務(wù)器使用相同的 ID 回復(fù)幀。
在 HTTP/2 中,我們對(duì) https://blog.cloudflare.com 的 GET 請(qǐng)求將通過流 ID 1 進(jìn)行交換,客戶端發(fā)送一個(gè) HEADERS 幀,服務(wù)器使用一個(gè) HEADERS 幀進(jìn)行響應(yīng),后跟一個(gè)或多個(gè) DATA 幀。 客戶端請(qǐng)求始終使用奇數(shù)流 ID,因此后續(xù)請(qǐng)求將使用流 ID 3、5 等。 可以以任何順序提供響應(yīng),并且來自不同流的幀可以交織。
流復(fù)用和并發(fā)是 HTTP/2 的強(qiáng)大功能。 它們可以更有效地使用單個(gè) TCP 連接。 HTTP/2 優(yōu)化了資源獲取,尤其是與優(yōu)先級(jí)結(jié)合使用時(shí)。 另一方面,與 HTTP/1.1 相比,使客戶端能夠輕松啟動(dòng)大量并行工作可能會(huì)增加對(duì)服務(wù)器資源的峰值需求。 這是一個(gè)明顯的拒絕服務(wù)向量。
為了提供一些防護(hù),HTTP/2 提供了最大活動(dòng)并發(fā)流的概念。 SETTINGS_MAX_CONCURRENT_STREAMS 參數(shù)允許服務(wù)器通告其并發(fā)限制。 例如,如果服務(wù)器規(guī)定限制為 100,則任何時(shí)候只能有 100 個(gè)請(qǐng)求處于活動(dòng)狀態(tài)。 如果客戶端嘗試打開超過此限制的流,則服務(wù)器必須使用 RST_STREAM 幀拒絕它。 流拒絕不會(huì)影響連接上的其他正在進(jìn)行的流。
真實(shí)的故事有點(diǎn)復(fù)雜。 流有生命周期。 下圖是 HTTP/2 流狀態(tài)機(jī)的示意圖。 客戶端和服務(wù)器管理自己的流狀態(tài)視圖。 HEADERS、DATA 和 RST_STREAM 幀在發(fā)送或接收時(shí)會(huì)觸發(fā)轉(zhuǎn)換。 雖然流狀態(tài)的視圖是獨(dú)立的,但它們是同步的。
HEADERS 和 DATA 幀包含 END_STREAM 標(biāo)志,當(dāng)設(shè)置為值 1(真)時(shí),可以觸發(fā)狀態(tài)轉(zhuǎn)換。
讓我們通過一個(gè)沒有消息內(nèi)容的 GET 請(qǐng)求示例來解決這個(gè)問題。 客戶端以 HEADERS 幀的形式發(fā)送請(qǐng)求,并將 END_STREAM 標(biāo)志設(shè)置為 1??蛻舳耸紫葘⒘鲝目臻e狀態(tài)轉(zhuǎn)換為打開狀態(tài),然后立即轉(zhuǎn)換為半關(guān)閉狀態(tài)。 客戶端半關(guān)閉狀態(tài)意味著它不能再發(fā)送HEADERS或DATA,只能發(fā)送 WINDOW_UPDATE、PRIORITY或RST_STREAM幀。 然而它可以接收任何幀。
一旦服務(wù)器接收并解析了 HEADERS 幀,它就會(huì)將流狀態(tài)從空閑轉(zhuǎn)變?yōu)榇蜷_,然后半關(guān)閉,因此它與客戶端匹配。 服務(wù)器半關(guān)閉狀態(tài)意味著它可以發(fā)送任何幀,但只能接收 WINDOW_UPDATE、PRIORITY 或 RST_STREAM 幀。
對(duì) GET 的響應(yīng)包含消息內(nèi)容,因此服務(wù)器發(fā)送 END_STREAM 標(biāo)志設(shè)置為 0 的 HEADERS,然后發(fā)送 END_STREAM 標(biāo)志設(shè)置為 1 的 DATA。DATA 幀觸發(fā)服務(wù)器上流從半關(guān)閉到關(guān)閉的轉(zhuǎn)換。 當(dāng)客戶端收到它時(shí),它也會(huì)轉(zhuǎn)換為關(guān)閉狀態(tài)。 一旦流關(guān)閉,就無法發(fā)送或接收任何幀。
將此生命周期應(yīng)用回并發(fā)上下文中,HTTP/2 指出:
處于“打開”狀態(tài)或任一“半關(guān)閉”狀態(tài)的流計(jì)入允許端點(diǎn)打開的最大流數(shù)。 處于這三種狀態(tài)中任何一種狀態(tài)的流都會(huì)計(jì)入 SETTINGS_MAX_CONCURRENT_STREAMS 設(shè)置中公布的限制。
理論上,并發(fā)限制是有用的。 然而,有一些實(shí)際因素阻礙了其有效性——我們將在本文后續(xù)介紹。
HTTP/2 請(qǐng)求取消
早些時(shí)候,我們討論了客戶取消傳遞中請(qǐng)求的情況。 HTTP/2 以比 HTTP/1.1 更有效的方式支持這一點(diǎn)。 客戶端可以為單個(gè)流發(fā)送 RST_STREAM 幀,而不需要拆除整個(gè)連接。 這指示服務(wù)器停止處理請(qǐng)求并中止響應(yīng),從而釋放服務(wù)器資源并避免浪費(fèi)帶寬。
讓我們考慮一下之前的 3 個(gè)請(qǐng)求的示例。 這次,在發(fā)送所有標(biāo)頭后,客戶端取消了流 1 上的請(qǐng)求。 服務(wù)器在準(zhǔn)備好提供響應(yīng)之前解析此 RST_STREAM 幀,并且僅響應(yīng)流 3 和 5:
請(qǐng)求取消是一個(gè)有用的功能。 例如,當(dāng)滾動(dòng)包含多個(gè)圖像的網(wǎng)頁(yè)時(shí),網(wǎng)絡(luò)瀏覽器可以取消落在視口之外的圖像,這意味著進(jìn)入視口的圖像可以更快地加載。 與 HTTP/1.1 相比,HTTP/2 使這種行為更加高效。
被取消的請(qǐng)求流會(huì)快速過渡整個(gè)流生命周期。 END_STREAM 標(biāo)志設(shè)置為 1 的客戶端 HEADERS 狀態(tài)從空閑狀態(tài)轉(zhuǎn)換為打開狀態(tài)再到半關(guān)閉狀態(tài),然后 RST_STREAM 立即導(dǎo)致從半關(guān)閉狀態(tài)轉(zhuǎn)換為關(guān)閉狀態(tài)。
回想一下,只有處于打開或半關(guān)閉狀態(tài)的流才會(huì)影響流并發(fā)限制。 當(dāng)客戶端取消流時(shí),它立即能夠在其位置打開另一個(gè)流,并可以立即發(fā)送另一個(gè)請(qǐng)求。 這是 CVE-2023-44487 發(fā)揮作用的關(guān)鍵。
快速重置導(dǎo)致拒絕服務(wù)
HTTP/2 請(qǐng)求取消可能被濫用來快速重置無限數(shù)量的流。 當(dāng) HTTP/2 服務(wù)器能夠足夠快地處理客戶端發(fā)送的 RST_STREAM 幀并拆除狀態(tài)時(shí),這種快速重置不會(huì)導(dǎo)致問題。 當(dāng)整理工作出現(xiàn)任何延誤或滯后時(shí),問題就會(huì)開始出現(xiàn)。 客戶端可能會(huì)處理大量請(qǐng)求,從而導(dǎo)致工作積壓,從而導(dǎo)致服務(wù)器上資源的過度消耗。
常見的 HTTP 部署架構(gòu)是在其他組件之前運(yùn)行 HTTP/2 代理或負(fù)載均衡器。 當(dāng)客戶端請(qǐng)求到達(dá)時(shí),它會(huì)被快速分派,并且實(shí)際工作在其他地方作為異步活動(dòng)完成。 這使得代理能夠非常有效地處理客戶端流量。 然而,這種關(guān)注點(diǎn)分離可能會(huì)使代理很難整理正在進(jìn)行的作業(yè)。 因此,這些部署更有可能遇到快速重置帶來的問題。
當(dāng) Cloudflare 的反向代理處理傳入的 HTTP/2 客戶端流量時(shí),它們會(huì)將數(shù)據(jù)從連接的套接字復(fù)制到緩沖區(qū)中,并按順序處理緩沖的數(shù)據(jù)。 當(dāng)讀取每個(gè)請(qǐng)求(標(biāo)頭和數(shù)據(jù)幀)時(shí),它被分派到上游服務(wù)。 當(dāng)讀取 RST_STREAM 幀時(shí),請(qǐng)求的本地狀態(tài)將被拆除,并通知上游請(qǐng)求已被取消。 沖洗并重復(fù),直到耗盡整個(gè)緩沖區(qū)。 然而,這種邏輯可能會(huì)被濫用:當(dāng)惡意客戶端開始發(fā)送大量請(qǐng)求鏈并在連接開始時(shí)重置時(shí),我們的服務(wù)器會(huì)急切地讀取所有請(qǐng)求,并對(duì)上游服務(wù)器造成壓力,導(dǎo)致無法處理任何新傳入的請(qǐng)求。
需要強(qiáng)調(diào)的重要一點(diǎn)是,流并發(fā)本身無法緩解快速重置。 無論服務(wù)器選擇的 SETTINGS_MAX_CONCURRENT_STREAMS 值如何,客戶端都可以攪動(dòng)請(qǐng)求以創(chuàng)建高請(qǐng)求率。
快速重置剖析
以下是使用概念驗(yàn)證客戶端嘗試發(fā)出總共 1000 個(gè)請(qǐng)求的快速重置示例。 我使用了現(xiàn)成的服務(wù)器,沒有任何緩解措施; 在測(cè)試環(huán)境中偵聽端口 443。 為了清楚起見,使用 Wireshark 剖析流量并進(jìn)行過濾以僅顯示 HTTP/2 流量。 下載 pcap 以進(jìn)行后續(xù)操作。
有點(diǎn)難看,因?yàn)橛泻芏鄮?我們可以通過Wireshark的Statistics > HTTP2工具得到一個(gè)快速的總結(jié):
此跟蹤中的第一幀(數(shù)據(jù)包 14 中)是服務(wù)器的 SETTINGS 幀,它通告最大流并發(fā)數(shù)為 100。在數(shù)據(jù)包 15 中,客戶端發(fā)送一些控制幀,然后開始發(fā)出快速重置的請(qǐng)求。 第一個(gè) HEADERS 幀長(zhǎng) 26 個(gè)字節(jié),所有后續(xù)的 HEADERS 只有 9 個(gè)字節(jié)。 這種大小差異是由于稱為 HPACK 的壓縮技術(shù)造成的。 數(shù)據(jù)包 15 總共包含 525 個(gè)請(qǐng)求,直至流 1051。
有趣的是,流 1051 的 RST_STREAM 不適合數(shù)據(jù)包 15,因此在數(shù)據(jù)包 16 中我們看到服務(wù)器以 404 響應(yīng)進(jìn)行響應(yīng)。 然后,在數(shù)據(jù)包 17 中,客戶端發(fā)送 RST_STREAM,然后繼續(xù)發(fā)送剩余的 475 個(gè)請(qǐng)求。
請(qǐng)注意,雖然服務(wù)器通告了 100 個(gè)并發(fā)流,但客戶端發(fā)送的兩個(gè)數(shù)據(jù)包發(fā)送的 HEADERS 幀比這多得多。 客戶端不必等待服務(wù)器的任何返回流量,它僅受其可以發(fā)送的數(shù)據(jù)包大小的限制。 在此跟蹤中沒有看到服務(wù)器 RST_STREAM 幀,這表明服務(wù)器沒有觀察到并發(fā)流違規(guī)。
對(duì)客戶的影響
如上所述,當(dāng)請(qǐng)求被取消時(shí),上游服務(wù)會(huì)收到通知,并可以在浪費(fèi)太多資源之前中止請(qǐng)求。 這次攻擊就是這種情況,大多數(shù)惡意請(qǐng)求從未轉(zhuǎn)發(fā)到源服務(wù)器。 然而,這些攻擊的規(guī)模確實(shí)造成了一些影響。
首先,隨著傳入請(qǐng)求的速率達(dá)到前所未有的峰值,我們收到了客戶發(fā)現(xiàn)的 502 錯(cuò)誤數(shù)量增加的報(bào)告。 這種情況發(fā)生在我們受影響最嚴(yán)重的數(shù)據(jù)中心,因?yàn)樗鼈冋谂μ幚硭姓?qǐng)求。讓我們更深入地了解細(xì)節(jié),重點(diǎn)關(guān)注傳入請(qǐng)求到達(dá)我們的數(shù)據(jù)中心之一時(shí)如何處理:
我們可以看到我們的基礎(chǔ)設(shè)施由一系列具有不同職責(zé)的不同代理服務(wù)器組成。 特別是,當(dāng)客戶端連接到 Cloudflare 發(fā)送 HTTPS 流量時(shí),它首先會(huì)命中我們的 TLS 解密代理:它解密 TLS 流量,處理 HTTP 1、2 或 3 流量,然后將其轉(zhuǎn)發(fā)到我們的“業(yè)務(wù)邏輯”代理。 它負(fù)責(zé)加載每個(gè)客戶的所有設(shè)置,然后將請(qǐng)求正確路由到其他上游服務(wù) - 更重要的是,在我們的例子中,它還負(fù)責(zé)安全功能。 這是處理 L7 攻擊緩解的地方。
這種攻擊媒介的問題在于它能夠在每個(gè)連接中非常快速地發(fā)送大量請(qǐng)求。 在我們有機(jī)會(huì)阻止它們之前,它們中的每一個(gè)都必須轉(zhuǎn)發(fā)到業(yè)務(wù)邏輯代理。 隨著請(qǐng)求吞吐量變得高于我們的代理容量,連接這兩個(gè)服務(wù)的管道在我們的一些服務(wù)器中達(dá)到了飽和水平。
發(fā)生這種情況時(shí),TLS 代理無法再連接到其上游代理,這就是為什么某些客戶端在最嚴(yán)重的攻擊期間看到“502 Bad Gateway”錯(cuò)誤的原因。 值得注意的是,截至今天,用于創(chuàng)建 HTTP 分析的日志也由我們的業(yè)務(wù)邏輯代理發(fā)出。 其結(jié)果是這些錯(cuò)誤在 Cloudflare 儀表板中不可見。 我們的內(nèi)部?jī)x表板顯示,大約 1% 的請(qǐng)求在第一波攻擊期間(在我們實(shí)施緩解措施之前)受到影響,在 8 月 29 日最嚴(yán)重的攻擊期間,峰值在 12% 左右,持續(xù)了幾秒鐘。 下圖顯示了發(fā)生這種情況時(shí)兩個(gè)小時(shí)內(nèi)這些錯(cuò)誤的比率:
我們?cè)诮酉聛淼膸滋炖锱Υ蠓鶞p少這個(gè)數(shù)字,本文稍后將詳細(xì)介紹。 由于我們堆棧的變化以及我們的緩解措施大大減少了這些攻擊的規(guī)模,今天這個(gè)數(shù)字實(shí)際上為零:
499錯(cuò)誤和HTTP/2流并發(fā)的挑戰(zhàn)
一些客戶報(bào)告的另一個(gè)癥狀是 499 錯(cuò)誤增加。 其原因有點(diǎn)不同,與本文前面詳細(xì)介紹的 HTTP/2 連接中的最大流并發(fā)有關(guān)。
HTTP/2 設(shè)置在連接開始時(shí)使用 SETTINGS 幀進(jìn)行交換。 如果沒有接收顯式參數(shù),則應(yīng)用默認(rèn)值。 一旦客戶端建立了 HTTP/2 連接,它就可以等待服務(wù)器的設(shè)置(慢),也可以采用默認(rèn)值并開始發(fā)出請(qǐng)求(快)。 對(duì)于 SETTINGS_MAX_CONCURRENT_STREAMS,默認(rèn)值實(shí)際上是無限制的(流 ID 使用 31 位數(shù)字空間,請(qǐng)求使用奇數(shù),因此實(shí)際限制為 1073741824)。 規(guī)范建議服務(wù)器提供不少于 100 個(gè)流。 客戶端通常偏向于速度,因此不要等待服務(wù)器設(shè)置,這會(huì)產(chǎn)生一些競(jìng)爭(zhēng)條件。 客戶端正在對(duì)服務(wù)器可能選擇的限制進(jìn)行賭博; 如果他們選擇錯(cuò)誤,請(qǐng)求將被拒絕并必須重試。 在 1073741824 流上賭博有點(diǎn)愚蠢。 相反,許多客戶端決定限制自己發(fā)出 100 個(gè)并發(fā)流,希望服務(wù)器遵循規(guī)范建議。 當(dāng)服務(wù)器選擇低于 100 的值時(shí),客戶端賭博就會(huì)失敗并且流會(huì)被重置。
服務(wù)器重置流超出并發(fā)限制的原因有很多。 HTTP/2 是嚴(yán)格的,要求在出現(xiàn)解析或邏輯錯(cuò)誤時(shí)關(guān)閉流。 2019 年,Cloudflare 開發(fā)了多種緩解措施來應(yīng)對(duì) HTTP/2 DoS 漏洞。 其中幾個(gè)漏洞是由客戶端行為不當(dāng)引起的,導(dǎo)致服務(wù)器重置流。 遏制此類客戶端的一個(gè)非常有效的策略是計(jì)算連接期間服務(wù)器重置的次數(shù),當(dāng)超過某個(gè)閾值時(shí),使用 GOAWAY 幀關(guān)閉連接。 合法客戶可能會(huì)在連接中犯一兩個(gè)錯(cuò)誤,這是可以接受的。 犯太多錯(cuò)誤的客戶端可能已損壞或惡意,關(guān)閉連接可以解決這兩種情況。
在響應(yīng) CVE-2023-44487 啟用的 DoS 攻擊時(shí),Cloudflare 將最大流并發(fā)數(shù)降低到 64。在進(jìn)行此更改之前,我們沒有意識(shí)到客戶端不會(huì)等待 SETTINGS,而是假設(shè)并發(fā)數(shù)為 100。某些網(wǎng)頁(yè),例如 作為一個(gè)圖片庫(kù),確實(shí)會(huì)導(dǎo)致瀏覽器在連接開始時(shí)立即發(fā)送 100 個(gè)請(qǐng)求。 不幸的是,超出限制的 36 個(gè)流都需要重置,這觸發(fā)了我們的計(jì)數(shù)緩解措施。 這意味著我們關(guān)閉了合法客戶端上的連接,導(dǎo)致頁(yè)面加載完全失敗。 當(dāng)我們意識(shí)到這個(gè)互操作性問題后,我們將最大流并發(fā)數(shù)更改為 100。
Cloudflare措施和建議
2019 年,發(fā)現(xiàn)了多個(gè)與 HTTP/2 實(shí)現(xiàn)相關(guān)的 DoS 漏洞。 Cloudflare 開發(fā)并部署了一系列檢測(cè)和緩解措施作為響應(yīng)。 CVE-2023-44487是HTTP/2漏洞的另一種表現(xiàn)形式。 然而,為了緩解這一問題,我們能夠擴(kuò)展現(xiàn)有的保護(hù)措施來監(jiān)視客戶端發(fā)送的 RST_STREAM 幀,并在它們被濫用時(shí)關(guān)閉連接。 RST_STREAM 的合法客戶端使用不受影響。
除了直接修復(fù)之外,我們還對(duì)服務(wù)器的 HTTP/2 幀處理和請(qǐng)求分派代碼進(jìn)行了多項(xiàng)改進(jìn)。 此外,業(yè)務(wù)邏輯服務(wù)器還對(duì)排隊(duì)和調(diào)度進(jìn)行了改進(jìn),減少了不必要的工作并提高了取消響應(yīng)能力。 這些共同減少了各種潛在濫用模式的影響,并為服務(wù)器在飽和之前提供了更多空間來處理請(qǐng)求。
盡早緩解攻擊
Cloudflare 已經(jīng)擁有適當(dāng)?shù)南到y(tǒng),可以通過更便宜的方法有效地緩解非常大的攻擊。 其中之一被命名為“IP Jail”。 對(duì)于超容量攻擊,該系統(tǒng)會(huì)收集參與攻擊的客戶端 IP,并阻止它們連接到受攻擊的財(cái)產(chǎn)(無論是在 IP 級(jí)別還是在我們的 TLS 代理中)。 然而,該系統(tǒng)需要幾秒鐘才能完全生效; 在這寶貴的幾秒鐘內(nèi),源頭已經(jīng)受到保護(hù),但我們的基礎(chǔ)設(shè)施仍然需要吸收所有 HTTP 請(qǐng)求。 由于這種新的僵尸網(wǎng)絡(luò)實(shí)際上沒有啟動(dòng)期,因此我們需要能夠在攻擊成為問題之前將其消滅。
為了實(shí)現(xiàn)這一目標(biāo),我們擴(kuò)展了 IP Jail 系統(tǒng)來保護(hù)我們的整個(gè)基礎(chǔ)設(shè)施:一旦 IP 被“監(jiān)禁”,不僅會(huì)阻止它連接到受攻擊的財(cái)產(chǎn),我們還會(huì)禁止相應(yīng)的 IP 使用 HTTP/2 訪問任何其他域 在 Cloudflare 上使用了一段時(shí)間。 由于使用 HTTP/1.x 不可能進(jìn)行此類協(xié)議濫用,因此這限制了攻擊者運(yùn)行大型攻擊的能力,而共享同一 IP 的任何合法客戶端在此期間只會(huì)看到非常小的性能下降。 基于 IP 的緩解措施是一種非常生硬的工具——這就是為什么我們?cè)诖笠?guī)模使用它們時(shí)必須非常小心,并盡可能避免誤報(bào)。 此外,僵尸網(wǎng)絡(luò)中給定 IP 的生命周期通常很短,因此任何長(zhǎng)期緩解措施都可能弊大于利。 下圖顯示了我們目睹的攻擊中 IP 的流失情況:
正如我們所看到的,在某一天發(fā)現(xiàn)的許多新 IP 隨后很快就消失了。
由于所有這些操作都發(fā)生在 HTTPS 管道開始處的 TLS 代理中,因此與常規(guī) L7 緩解系統(tǒng)相比,這可以節(jié)省大量資源。 這使我們能夠更順利地抵御這些攻擊,現(xiàn)在由這些僵尸網(wǎng)絡(luò)引起的隨機(jī) 502 錯(cuò)誤數(shù)量已降至零。
攻擊可觀測(cè)性改進(jìn)
我們正在做出改變的另一個(gè)方面是可觀察性。 在客戶分析中不可見的情況下向客戶返回錯(cuò)誤是不令人滿意的。 幸運(yùn)的是,早在最近的攻擊發(fā)生之前,一個(gè)對(duì)這些系統(tǒng)進(jìn)行徹底檢修的項(xiàng)目就已經(jīng)開始進(jìn)行。 最終,它將允許我們基礎(chǔ)設(shè)施中的每個(gè)服務(wù)記錄自己的數(shù)據(jù),而不是依賴我們的業(yè)務(wù)邏輯代理來合并和發(fā)出日志數(shù)據(jù)。 這次事件凸顯了這項(xiàng)工作的重要性,我們正在加倍努力。
我們還致力于更好的連接級(jí)日志記錄,使我們能夠更快地發(fā)現(xiàn)此類協(xié)議濫用,從而提高我們的 DDoS 緩解能力。
結(jié)論
雖然這是最新的破紀(jì)錄攻擊,但我們知道這不會(huì)是最后一次。 隨著攻擊變得越來越復(fù)雜,Cloudflare 不斷努力主動(dòng)識(shí)別新威脅 - 為我們的全球網(wǎng)絡(luò)部署對(duì)策,以便我們數(shù)百萬(wàn)的客戶立即得到自動(dòng)保護(hù)。
自 2017 年以來,Cloudflare 一直為我們的所有客戶提供免費(fèi)、不計(jì)量且無限制的 DDoS 保護(hù)。此外,我們還提供一系列附加安全功能,以滿足各種規(guī)模組織的需求。 如果您不確定自己是否受到保護(hù)或想了解如何受到保護(hù)。